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. + * + *

+ * <bean id="myTargetConnectionFactory" class="org.springframework.jndi.JndiObjectFactoryBean">
+ *   <property name="jndiName" value="java:comp/env/jms/mycf"/>
+ * </bean>
+ *
+ * <bean id="myConnectionFactory" class="org.springframework.jms.connection.UserCredentialsConnectionFactoryAdapter">
+ *   <property name="targetConnectionFactory" ref="myTargetConnectionFactory"/>
+ *   <property name="username" value="myusername"/>
+ *   <property name="password" value="mypassword"/>
+ * </bean>
+ * + *

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's send(..) 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: + *

+ * The exact behavior might vary according to the concrete listener container + * and JMS provider used. + * + *

There are two solutions to the duplicate processing problem: + *

+ * Note that XA transaction coordination adds significant runtime overhead, + * so it might be feasible to avoid it unless absolutely necessary. + * + *

Recommendations: + *

+ * + *

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. + * + *

public interface MessageContentsDelegate {
+ *    void handleMessage(String text);
+ *    void handleMessage(Map map);
+ *    void handleMessage(byte[] bytes);
+ *    void handleMessage(Serializable obj);
+ * }
+ * + * 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. + * + *
public interface RawMessageDelegate {
+ *    void handleMessage(TextMessage message);
+ *    void handleMessage(MapMessage message);
+ *    void handleMessage(BytesMessage message);
+ *    void handleMessage(ObjectMessage message);
+ * }
+ * + * 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. + * + *
public interface TextMessageContentDelegate {
+ *    void onMessage(String text);
+ * }
+ * + * 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. + * + *
public interface ResponsiveTextMessageContentDelegate {
+ *    String handleMessage(String text);
+ * }
+ * + * 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. + *

Uses the JMS pub-sub API if the given destination is a topic, + * else uses the JMS queue API. + */ + protected void sendResponse(Session session, Destination destination, Message response) throws JMSException { + MessageProducer producer = null; + try { + if (destination instanceof Topic) { + producer = ((TopicSession) session).createPublisher((Topic) destination); + postProcessProducer(producer, response); + ((TopicPublisher) producer).publish(response); + } + else { + producer = ((QueueSession) session).createSender((Queue) destination); + postProcessProducer(producer, response); + ((QueueSender) producer).send(response); + } + } + finally { + JmsUtils.closeMessageProducer(producer); + } + } + +} Index: 3rdParty_sources/spring/org/springframework/jms/listener/adapter/package.html =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jms/listener/adapter/package.html,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/jms/listener/adapter/package.html 17 Aug 2012 15:15:29 -0000 1.1 @@ -0,0 +1,9 @@ + + + +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 + * beans Map. + * @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 + * beans Map. + * @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 + * beans Map. + * @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: + *

+ * + * @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 mappings Properties + * 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: + * + *

+ * <bean class="org.springframework.jndi.JndiObjectFactoryBean">
+ *   <property name="jndiName" value="java:comp/env/jmx/runtime"/>
+ * </bean>
+ * + * @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: + * + *

+ * <bean class="org.springframework.jndi.JndiObjectFactoryBean">
+ *   <property name="jndiName" value="java:comp/env/jmx/runtime"/>
+ * </bean>
+ * + * @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). + * + *

Example: + * + *

+ * <bean id="queueConnectionFactoryTarget" class="org.springframework.jndi.JndiObjectTargetSource">
+ *   <property name="jndiName" value="JmsQueueConnectionFactory"/>
+ *   <property name="lookupOnStartup" value="false"/>
+ * </bean>
+ *
+ * <bean id="queueConnectionFactory" class="org.springframework.aop.framework.ProxyFactoryBean">
+ *   <property name="proxyInterfaces" value="javax.jms.QueueConnectionFactory"/>
+ *   <property name="targetSource" ref="queueConnectionFactoryTarget"/>
+ * </bean>
+ * + * 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: + * + *

+ * mailSender.send(new MimeMessagePreparator() {
+ *   public void prepare(MimeMessage mimeMessage) throws MessagingException {
+ *     MimeMessageHelper message = new MimeMessageHelper(mimeMessage, true, "UTF-8");
+ *     message.setFrom("me@mail.com");
+ *     message.setTo("you@mail.com");
+ *     message.setSubject("my subject");
+ *     message.setText("my text <img src='cid:myLogo'>", true);
+ *     message.addInline("myLogo", new ClassPathResource("img/mylogo.gif"));
+ *     message.addAttachment("myDocument.pdf", new ClassPathResource("doc/myDocument.pdf"));
+ *   }
+ * });
+ * + * 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} after setText; + * 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} after setText; + * 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} after setText; + * 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 addInline after {@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 addInline after {@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 addInline after {@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 addInline after 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 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. + * + *

Please see the + * + * Commons Attributes documentation for information on how to use the + * attribute compiler. + * + *

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: + * + *

+ * <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
+ *   ...
+ *   <property name="filterDefinitions">
+ *     <list>
+ *       <bean class="org.springframework.orm.hibernate3.FilterDefinitionFactoryBean">
+ *         <property name="filterName" value="myFilter"/>
+ *         <property name="parameterTypes">
+ *           <props>
+ *             <prop key="myParam">string</prop>
+ *             <prop key="myOtherParam">long</prop>
+ *           </props>
+ *         </property>
+ *       </bean>
+ *     </list>
+ *   </property>
+ *   ...
+ * </bean>
+ * + * 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. + *

For example: + *

+	 * <property name="entityCacheStrategies">
+	 *   <props>
+	 *     <prop key="com.mycompany.Customer">read-write</prop>
+	 *     <prop key="com.mycompany.Product">read-only,myRegion</prop>
+	 *   </props>
+	 * </property>
+ * 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. + *

For example: + *

+	 * <property name="collectionCacheStrategies">
+	 *   <props>
+	 *     <prop key="com.mycompany.Order.items">read-write</prop>
+	 *     <prop key="com.mycompany.Product.categories">read-only,myRegion</prop>
+	 *   </props>
+	 * </property>
+ * 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: + * + *

+ * <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
+ *   ...
+ *   <property name="typeDefinitions">
+ *     <list>
+ *       <bean class="org.springframework.orm.hibernate3.TypeDefinitionBean">
+ *         <property name="typeName" value="myType"/>
+ *         <property name="typeClass" value="mypackage.MyTypeClass"/>
+ *       </bean>
+ *     </list>
+ *   </property>
+ *   ...
+ * </bean>
+ * + * 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: + * + *

+ * <bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
+ *   <property name="dataSource" ref="dataSource"/>
+ *   <property name="annotatedClasses">
+ *     <list>
+ *       <value>test.package.Foo</value>
+ *       <value>test.package.Bar</value>
+ *     </list>
+ *   </property>
+ * </bean>
+ * + * Or when using classpath scanning for autodetection of entity classes: + * + *
+ * <bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
+ *   <property name="dataSource" ref="dataSource"/>
+ *   <property name="packagesToScan" value="test.package"/>
+ * </bean>
+ * + * @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. + * + *

Usage example: + * + *

+ * <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
+ *   ...
+ *   <property name="entityInterceptor">
+ *     <bean class="org.springframework.orm.hibernate3.support.ScopedBeanInterceptor"/>
+ *   </property>
+ * </bean>
+ * + * @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: + * + *

+ * getSqlMapClientTemplate().execute(new SqlMapClientCallback() {
+ * 	 public Object doInSqlMapClient(SqlMapExecutor executor) throws SQLException {
+ * 		 executor.startBatch();
+ * 		 executor.update("insertSomething", "myParamValue");
+ * 		 executor.update("insertSomethingElse", "myOtherParamValue");
+ * 		 executor.executeBatch();
+ * 		 return null;
+ * 	 }
+ * });
+ * + * 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: + * + *

+ * public void doSomeDataAccessAction() {
+ *   PersistenceManager pm = PersistenceManagerFactoryUtils.getPersistenceManager(this.pmf, false);
+ *   ...
+ * }
+ * + *

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). + * + *

For example, in case of JPOX: + * + *

+ * <bean id="persistenceManagerFactory" class="org.jpox.PersistenceManagerFactoryImpl" destroy-method="close">
+ *   <property name="connectionFactory" ref="dataSource"/>
+ *   <property name="nontransactionalRead" value="true"/>
+ * </bean>
+ * 
+ * + *

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 entityManagerFactoryInterface; + + private Class 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 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 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 emInterface) { + Assert.isAssignable(EntityManager.class, emInterface); + this.entityManagerInterface = emInterface; + } + + public Class 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 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 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: + * + *

+ * public void doSomeDataAccessAction() {
+ *   this.entityManager...
+ * }
+ * + *

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 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 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: + * + *

+ * <bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor"/>
+ * + * 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: + * + *
+ * <bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor">
+ *   <property name="persistenceUnits">
+ *     <map/gt;
+ *       <entry key="unit1" value="persistence/unit1"/>
+ *       <entry key="unit2" value="persistence/unit2"/>
+ *     </map/gt;
+ *   </property>
+ * </bean>
+ * + * 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: + * + *

+ * <bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor">
+ *   <property name="persistenceContexts">
+ *     <map/gt;
+ *       <entry key="unit1" value="persistence/context1"/>
+ *       <entry key="unit2" value="persistence/context2"/>
+ *     </map/gt;
+ *   </property>
+ * </bean>
+ * + * 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 extendedEntityManagersToClose = + new ConcurrentHashMap(); + + + public PersistenceAnnotationBeanPostProcessor() { + setResourceRef(true); + } + + + /** + * Specify the persistence units for EntityManagerFactory lookups, + * as a Map from persistence unit name to persistence unit JNDI name + * (which needs to resolve to an EntityManagerFactory instance). + *

JNDI names specified here should refer to persistence-unit-ref + * entries in the Java EE deployment descriptor, matching the target persistence unit. + *

In case of no unit name specified in the annotation, the specified value + * for the {@link #setDefaultPersistenceUnitName default persistence unit} + * will be taken (by default, the value mapped to the empty String), + * or simply the single persistence unit if there is only one. + *

This is mainly intended for use in a Java EE 5 environment, with all + * lookup driven by the standard JPA annotations, and all EntityManagerFactory + * references obtained from JNDI. No separate EntityManagerFactory bean + * definitions are necessary in such a scenario. + *

If no corresponding "persistenceContexts"/"extendedPersistenceContexts" + * are specified, @PersistenceContext will be resolved to + * EntityManagers built on top of the EntityManagerFactory defined here. + * Note that those will be Spring-managed EntityManagers, which implement + * transaction synchronization based on Spring's facilities. + * If you prefer the Java EE 5 server's own EntityManager handling, + * specify corresponding "persistenceContexts"/"extendedPersistenceContexts". + */ + public void setPersistenceUnits(Map persistenceUnits) { + this.persistenceUnits = persistenceUnits; + } + + /** + * Specify the transactional persistence contexts for EntityManager lookups, + * as a Map from persistence unit name to persistence context JNDI name + * (which needs to resolve to an EntityManager instance). + *

JNDI names specified here should refer to persistence-context-ref + * entries in the Java EE deployment descriptors, matching the target persistence unit + * and being set up with persistence context type Transaction. + *

In case of no unit name specified in the annotation, the specified value + * for the {@link #setDefaultPersistenceUnitName default persistence unit} + * will be taken (by default, the value mapped to the empty String), + * or simply the single persistence unit if there is only one. + *

This is mainly intended for use in a Java EE 5 environment, with all + * lookup driven by the standard JPA annotations, and all EntityManager + * references obtained from JNDI. No separate EntityManagerFactory bean + * definitions are necessary in such a scenario, and all EntityManager + * handling is done by the Java EE 5 server itself. + */ + public void setPersistenceContexts(Map persistenceContexts) { + this.persistenceContexts = persistenceContexts; + } + + /** + * Specify the extended persistence contexts for EntityManager lookups, + * as a Map from persistence unit name to persistence context JNDI name + * (which needs to resolve to an EntityManager instance). + *

JNDI names specified here should refer to persistence-context-ref + * entries in the Java EE deployment descriptors, matching the target persistence unit + * and being set up with persistence context type Extended. + *

In case of no unit name specified in the annotation, the specified value + * for the {@link #setDefaultPersistenceUnitName default persistence unit} + * will be taken (by default, the value mapped to the empty String), + * or simply the single persistence unit if there is only one. + *

This is mainly intended for use in a Java EE 5 environment, with all + * lookup driven by the standard JPA annotations, and all EntityManager + * references obtained from JNDI. No separate EntityManagerFactory bean + * definitions are necessary in such a scenario, and all EntityManager + * handling is done by the Java EE 5 server itself. + */ + public void setExtendedPersistenceContexts(Map extendedPersistenceContexts) { + this.extendedPersistenceContexts = extendedPersistenceContexts; + } + + /** + * Specify the default persistence unit name, to be used in case + * of no unit name specified in an @PersistenceUnit / + * @PersistenceContext annotation. + *

This is mainly intended for lookups in the application context, + * indicating the target persistence unit name (typically matching + * the bean name), but also applies to lookups in the + * {@link #setPersistenceUnits "persistenceUnits"} / + * {@link #setPersistenceContexts "persistenceContexts"} / + * {@link #setExtendedPersistenceContexts "extendedPersistenceContexts"} map, + * avoiding the need for duplicated mappings for the empty String there. + *

Default is to check for a single EntityManagerFactory bean + * in the Spring application context, if any. If there are multiple + * such factories, either specify this default persistence unit name + * or explicitly refer to named persistence units in your annotations. + */ + public void setDefaultPersistenceUnitName(String unitName) { + this.defaultPersistenceUnitName = (unitName != null ? unitName : ""); + } + + public void setOrder(int order) { + this.order = order; + } + + public int getOrder() { + return this.order; + } + + public void setBeanFactory(BeanFactory beanFactory) { + if (beanFactory instanceof ListableBeanFactory) { + this.beanFactory = (ListableBeanFactory) beanFactory; + } + } + + + public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class beanType, String beanName) { + if (beanType != null) { + InjectionMetadata metadata = findPersistenceMetadata(beanType); + metadata.checkConfigMembers(beanDefinition); + } + } + + public Object postProcessBeforeInstantiation(Class beanClass, String beanName) throws BeansException { + return null; + } + + public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException { + InjectionMetadata metadata = findPersistenceMetadata(bean.getClass()); + try { + metadata.injectFields(bean, beanName); + } + catch (Throwable ex) { + throw new BeanCreationException(beanName, "Injection of persistence fields failed", ex); + } + return true; + } + + public PropertyValues postProcessPropertyValues( + PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException { + + InjectionMetadata metadata = findPersistenceMetadata(bean.getClass()); + try { + metadata.injectMethods(bean, beanName, pvs); + } + catch (Throwable ex) { + throw new BeanCreationException(beanName, "Injection of persistence methods failed", ex); + } + return pvs; + } + + public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { + return bean; + } + + public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { + return bean; + } + + public void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException { + EntityManager emToClose = this.extendedEntityManagersToClose.remove(bean); + EntityManagerFactoryUtils.closeEntityManager(emToClose); + } + + + private InjectionMetadata findPersistenceMetadata(final Class clazz) { + // Quick check on the concurrent map first, with minimal locking. + InjectionMetadata metadata = this.injectionMetadataCache.get(clazz); + if (metadata == null) { + synchronized (this.injectionMetadataCache) { + metadata = this.injectionMetadataCache.get(clazz); + if (metadata == null) { + final InjectionMetadata newMetadata = new InjectionMetadata(clazz); + ReflectionUtils.doWithFields(clazz, new ReflectionUtils.FieldCallback() { + public void doWith(Field field) { + PersistenceContext pc = field.getAnnotation(PersistenceContext.class); + PersistenceUnit pu = field.getAnnotation(PersistenceUnit.class); + if (pc != null || pu != null) { + if (Modifier.isStatic(field.getModifiers())) { + throw new IllegalStateException("Persistence annotations are not supported on static fields"); + } + newMetadata.addInjectedField(new PersistenceElement(field, null)); + } + } + }); + ReflectionUtils.doWithMethods(clazz, new ReflectionUtils.MethodCallback() { + public void doWith(Method method) { + PersistenceContext pc = method.getAnnotation(PersistenceContext.class); + PersistenceUnit pu = method.getAnnotation(PersistenceUnit.class); + if (pc != null || pu != null && + method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) { + if (Modifier.isStatic(method.getModifiers())) { + throw new IllegalStateException("Persistence annotations are not supported on static methods"); + } + if (method.getParameterTypes().length != 1) { + throw new IllegalStateException("Persistence annotation requires a single-arg method: " + method); + } + PropertyDescriptor pd = BeanUtils.findPropertyForMethod(method); + newMetadata.addInjectedMethod(new PersistenceElement(method, pd)); + } + } + }); + metadata = newMetadata; + this.injectionMetadataCache.put(clazz, metadata); + } + } + } + return metadata; + } + + /** + * Return a specified persistence unit for the given unit name, + * as defined through the "persistenceUnits" map. + * @param unitName the name of the persistence unit + * @return the corresponding EntityManagerFactory, + * or null if none found + * @see #setPersistenceUnits + */ + protected EntityManagerFactory getPersistenceUnit(String unitName) { + if (this.persistenceUnits != null) { + String unitNameForLookup = (unitName != null ? unitName : ""); + if ("".equals(unitNameForLookup)) { + unitNameForLookup = this.defaultPersistenceUnitName; + } + String jndiName = this.persistenceUnits.get(unitNameForLookup); + if (jndiName == null && "".equals(unitNameForLookup) && this.persistenceUnits.size() == 1) { + jndiName = this.persistenceUnits.values().iterator().next(); + } + if (jndiName != null) { + try { + return (EntityManagerFactory) lookup(jndiName, EntityManagerFactory.class); + } + catch (NamingException ex) { + throw new IllegalStateException("Could not obtain EntityManagerFactory [" + jndiName + "] from JNDI", ex); + } + } + } + return null; + } + + /** + * Return a specified persistence context for the given unit name, as defined + * through the "persistenceContexts" (or "extendedPersistenceContexts") map. + * @param unitName the name of the persistence unit + * @param extended whether to obtain an extended persistence context + * @return the corresponding EntityManager, or null if none found + * @see #setPersistenceContexts + * @see #setExtendedPersistenceContexts + */ + protected EntityManager getPersistenceContext(String unitName, boolean extended) { + Map contexts = (extended ? this.extendedPersistenceContexts : this.persistenceContexts); + if (contexts != null) { + String unitNameForLookup = (unitName != null ? unitName : ""); + if ("".equals(unitNameForLookup)) { + unitNameForLookup = this.defaultPersistenceUnitName; + } + String jndiName = contexts.get(unitNameForLookup); + if (jndiName == null && "".equals(unitNameForLookup) && contexts.size() == 1) { + jndiName = contexts.values().iterator().next(); + } + if (jndiName != null) { + try { + return (EntityManager) lookup(jndiName, EntityManager.class); + } + catch (NamingException ex) { + throw new IllegalStateException("Could not obtain EntityManager [" + jndiName + "] from JNDI", ex); + } + } + } + return null; + } + + /** + * Find an EntityManagerFactory with the given name in the current Spring + * application context, falling back to a single default EntityManagerFactory + * (if any) in case of no unit name specified. + * @param unitName the name of the persistence unit (may be null or empty) + * @param requestingBeanName the name of the requesting bean + * @return the EntityManagerFactory + * @throws NoSuchBeanDefinitionException if there is no such EntityManagerFactory in the context + */ + protected EntityManagerFactory findEntityManagerFactory(String unitName, String requestingBeanName) + throws NoSuchBeanDefinitionException { + + if (this.beanFactory == null) { + throw new IllegalStateException("ListableBeanFactory required for EntityManagerFactory bean lookup"); + } + String unitNameForLookup = (unitName != null ? unitName : ""); + if ("".equals(unitNameForLookup)) { + unitNameForLookup = this.defaultPersistenceUnitName; + } + if (!"".equals(unitNameForLookup)) { + return findNamedEntityManagerFactory(unitNameForLookup, requestingBeanName); + } + else { + return findDefaultEntityManagerFactory(requestingBeanName); + } + } + + /** + * Find an EntityManagerFactory with the given name in the current + * Spring application context. + * @param unitName the name of the persistence unit (never empty) + * @param requestingBeanName the name of the requesting bean + * @return the EntityManagerFactory + * @throws NoSuchBeanDefinitionException if there is no such EntityManagerFactory in the context + */ + protected EntityManagerFactory findNamedEntityManagerFactory(String unitName, String requestingBeanName) + throws NoSuchBeanDefinitionException { + + EntityManagerFactory emf = EntityManagerFactoryUtils.findEntityManagerFactory(this.beanFactory, unitName); + if (this.beanFactory instanceof ConfigurableBeanFactory) { + ((ConfigurableBeanFactory) this.beanFactory).registerDependentBean(unitName, requestingBeanName); + } + return emf; + } + + /** + * Find a single default EntityManagerFactory in the Spring application context. + * @return the default EntityManagerFactory + * @throws NoSuchBeanDefinitionException if there is no single EntityManagerFactory in the context + */ + protected EntityManagerFactory findDefaultEntityManagerFactory(String requestingBeanName) + throws NoSuchBeanDefinitionException{ + + String[] beanNames = + BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.beanFactory, EntityManagerFactory.class); + if (beanNames.length == 1) { + String unitName = beanNames[0]; + EntityManagerFactory emf = (EntityManagerFactory) this.beanFactory.getBean(unitName); + if (this.beanFactory instanceof ConfigurableBeanFactory) { + ((ConfigurableBeanFactory) this.beanFactory).registerDependentBean(unitName, requestingBeanName); + } + return emf; + } + else { + throw new NoSuchBeanDefinitionException( + EntityManagerFactory.class, "expected single bean but found " + beanNames.length); + } + } + + + /** + * Class representing injection information about an annotated field + * or setter method. + */ + private class PersistenceElement extends InjectionMetadata.InjectedElement { + + private final String unitName; + + private PersistenceContextType type; + + private Properties properties; + + public PersistenceElement(Member member, PropertyDescriptor pd) { + super(member, pd); + AnnotatedElement ae = (AnnotatedElement) member; + PersistenceContext pc = ae.getAnnotation(PersistenceContext.class); + PersistenceUnit pu = ae.getAnnotation(PersistenceUnit.class); + Class resourceType = EntityManager.class; + if (pc != null) { + if (pu != null) { + throw new IllegalStateException("Member may only be annotated with either " + + "@PersistenceContext or @PersistenceUnit, not both: " + member); + } + Properties properties = null; + PersistenceProperty[] pps = pc.properties(); + if (!ObjectUtils.isEmpty(pps)) { + properties = new Properties(); + for (int i = 0; i < pps.length; i++) { + PersistenceProperty pp = pps[i]; + properties.setProperty(pp.name(), pp.value()); + } + } + this.unitName = pc.unitName(); + this.type = pc.type(); + this.properties = properties; + } + else { + resourceType = EntityManagerFactory.class; + this.unitName = pu.unitName(); + } + checkResourceType(resourceType); + } + + /** + * Resolve the object against the application context. + */ + @Override + protected Object getResourceToInject(Object target, String requestingBeanName) { + // Resolves to EntityManagerFactory or EntityManager. + if (this.type != null) { + return (this.type == PersistenceContextType.EXTENDED ? + resolveExtendedEntityManager(target, requestingBeanName) : + resolveEntityManager(requestingBeanName)); + } + else { + // OK, so we need an EntityManagerFactory... + return resolveEntityManagerFactory(requestingBeanName); + } + } + + private EntityManagerFactory resolveEntityManagerFactory(String requestingBeanName) { + // Obtain EntityManagerFactory from JNDI? + EntityManagerFactory emf = getPersistenceUnit(this.unitName); + if (emf == null) { + // Need to search for EntityManagerFactory beans. + emf = findEntityManagerFactory(this.unitName, requestingBeanName); + } + return emf; + } + + private EntityManager resolveEntityManager(String requestingBeanName) { + // Obtain EntityManager reference from JNDI? + EntityManager em = getPersistenceContext(this.unitName, false); + if (em == null) { + // No pre-built EntityManager found -> build one based on factory. + // Obtain EntityManagerFactory from JNDI? + EntityManagerFactory emf = getPersistenceUnit(this.unitName); + if (emf == null) { + // Need to search for EntityManagerFactory beans. + emf = findEntityManagerFactory(this.unitName, requestingBeanName); + } + // Inject a shared transactional EntityManager proxy. + if (emf instanceof EntityManagerFactoryInfo && + ((EntityManagerFactoryInfo) emf).getEntityManagerInterface() != null) { + // Create EntityManager based on the info's vendor-specific type + // (which might be more specific than the field's type). + em = SharedEntityManagerCreator.createSharedEntityManager(emf, this.properties); + } + else { + // Create EntityManager based on the field's type. + em = SharedEntityManagerCreator.createSharedEntityManager(emf, this.properties, getResourceType()); + } + } + return em; + } + + private EntityManager resolveExtendedEntityManager(Object target, String requestingBeanName) { + // Obtain EntityManager reference from JNDI? + EntityManager em = getPersistenceContext(this.unitName, true); + if (em == null) { + // No pre-built EntityManager found -> build one based on factory. + // Obtain EntityManagerFactory from JNDI? + EntityManagerFactory emf = getPersistenceUnit(this.unitName); + if (emf == null) { + // Need to search for EntityManagerFactory beans. + emf = findEntityManagerFactory(this.unitName, requestingBeanName); + } + // Inject a container-managed extended EntityManager. + em = ExtendedEntityManagerCreator.createContainerManagedEntityManager(emf, this.properties); + } + if (em instanceof EntityManagerProxy && + beanFactory != null && !beanFactory.isPrototype(requestingBeanName)) { + extendedEntityManagersToClose.put(target, ((EntityManagerProxy) em).getTargetEntityManager()); + } + return em; + } + } + +} Index: 3rdParty_sources/spring/org/springframework/orm/jpa/support/SharedEntityManagerBean.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/jpa/support/SharedEntityManagerBean.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/orm/jpa/support/SharedEntityManagerBean.java 17 Aug 2012 15:16:15 -0000 1.1 @@ -0,0 +1,119 @@ +/* + * 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.beans.factory.FactoryBean; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.orm.jpa.EntityManagerFactoryAccessor; +import org.springframework.orm.jpa.EntityManagerFactoryInfo; +import org.springframework.orm.jpa.EntityManagerPlus; +import org.springframework.orm.jpa.JpaDialect; +import org.springframework.orm.jpa.SharedEntityManagerCreator; +import org.springframework.util.Assert; + +/** + * {@link FactoryBean} that exposes a shared JPA {@link javax.persistence.EntityManager} + * reference for a given EntityManagerFactory. Typically used for an EntityManagerFactory + * created by {@link org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean}, + * as direct alternative to a JNDI lookup for a Java EE 5 server's EntityManager reference. + * + *

The shared 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. + * + *

Can be passed to DAOs that expect a shared EntityManager reference rather than an + * EntityManagerFactory. Note that Spring's {@link org.springframework.orm.jpa.JpaTransactionManager} + * always needs an EntityManagerFactory in order to create new transactional EntityManager instances. + * + * @author Juergen Hoeller + * @since 2.0 + * @see #setEntityManagerFactory + * @see #setEntityManagerInterface + * @see org.springframework.orm.jpa.LocalEntityManagerFactoryBean + * @see org.springframework.orm.jpa.JpaTransactionManager + */ +public class SharedEntityManagerBean extends EntityManagerFactoryAccessor implements FactoryBean, InitializingBean { + + private Class entityManagerInterface; + + private EntityManager shared; + + + /** + * Specify the EntityManager interface to expose. + *

Default is the the EntityManager interface as defined by the + * EntityManagerFactoryInfo, if available. Else, the standard + * javax.persistence.EntityManager interface will be used. + * @see org.springframework.orm.jpa.EntityManagerFactoryInfo#getEntityManagerInterface() + * @see javax.persistence.EntityManager + */ + public void setEntityManagerInterface(Class entityManagerInterface) { + Assert.notNull(entityManagerInterface, "entityManagerInterface must not be null"); + Assert.isAssignable(EntityManager.class, entityManagerInterface); + this.entityManagerInterface = entityManagerInterface; + } + + + public final void afterPropertiesSet() { + EntityManagerFactory emf = getEntityManagerFactory(); + if (emf == null) { + throw new IllegalArgumentException("entityManagerFactory is required"); + } + Class[] ifcs = null; + if (emf instanceof EntityManagerFactoryInfo) { + EntityManagerFactoryInfo emfInfo = (EntityManagerFactoryInfo) emf; + if (this.entityManagerInterface == null) { + this.entityManagerInterface = emfInfo.getEntityManagerInterface(); + if (this.entityManagerInterface == null) { + this.entityManagerInterface = EntityManager.class; + } + } + JpaDialect jpaDialect = emfInfo.getJpaDialect(); + if (jpaDialect != null && jpaDialect.supportsEntityManagerPlusOperations()) { + ifcs = new Class[] {this.entityManagerInterface, EntityManagerPlus.class}; + } + else { + ifcs = new Class[] {this.entityManagerInterface}; + } + } + else { + if (this.entityManagerInterface == null) { + this.entityManagerInterface = EntityManager.class; + } + ifcs = new Class[] {this.entityManagerInterface}; + } + this.shared = SharedEntityManagerCreator.createSharedEntityManager(emf, getJpaPropertyMap(), ifcs); + } + + + public EntityManager getObject() { + return this.shared; + } + + public Class getObjectType() { + return this.entityManagerInterface; + } + + public boolean isSingleton() { + return true; + } + +} Index: 3rdParty_sources/spring/org/springframework/orm/jpa/support/package.html =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/jpa/support/package.html,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/orm/jpa/support/package.html 17 Aug 2012 15:16:15 -0000 1.1 @@ -0,0 +1,8 @@ + + + +Classes supporting the org.springframework.orm.jpa package. +Contains a DAO base class for JpaTemplate usage. + + + Index: 3rdParty_sources/spring/org/springframework/orm/jpa/vendor/AbstractJpaVendorAdapter.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/jpa/vendor/AbstractJpaVendorAdapter.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/orm/jpa/vendor/AbstractJpaVendorAdapter.java 17 Aug 2012 15:16:13 -0000 1.1 @@ -0,0 +1,141 @@ +/* + * 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.vendor; + +import java.util.Map; + +import javax.persistence.EntityManager; +import javax.persistence.EntityManagerFactory; + +import org.springframework.orm.jpa.JpaDialect; +import org.springframework.orm.jpa.JpaVendorAdapter; + +/** + * Abstract {@link JpaVendorAdapter} implementation that defines common properties, + * to be translated into vendor-specific JPA properties by concrete subclasses. + * + * @author Juergen Hoeller + * @author Rod Johnson + * @since 2.0 + */ +public abstract class AbstractJpaVendorAdapter implements JpaVendorAdapter { + + private Database database = Database.DEFAULT; + + private String databasePlatform; + + private boolean generateDdl = false; + + private boolean showSql = false; + + + /** + * Specify the target database to operate on, as a value of the Database enum: + * DB2, DERBY, H2, HSQL, INFORMIX, MYSQL, ORACLE, POSTGRESQL, SQL_SERVER, SYBASE + */ + public void setDatabase(Database database) { + this.database = database; + } + + /** + * Return the target database to operate on. + */ + protected Database getDatabase() { + return this.database; + } + + /** + * Specify the name of the target database to operate on. + * The supported values are vendor-dependent platform identifiers. + */ + public void setDatabasePlatform(String databasePlatform) { + this.databasePlatform = databasePlatform; + } + + /** + * Return the name of the target database to operate on. + */ + protected String getDatabasePlatform() { + return this.databasePlatform; + } + + /** + * Set whether to generate DDL after the EntityManagerFactory has been initialized, + * creating/updating all relevant tables. + *

Note that the exact semantics of this flag depend on the underlying + * persistence provider. For any more advanced needs, specify the appropriate + * vendor-specific settings as "jpaProperties". + * @see org.springframework.orm.jpa.AbstractEntityManagerFactoryBean#setJpaProperties + */ + public void setGenerateDdl(boolean generateDdl) { + this.generateDdl = generateDdl; + } + + /** + * Return whether to generate DDL after the EntityManagerFactory has been initialized + * creating/updating all relevant tables. + */ + protected boolean isGenerateDdl() { + return this.generateDdl; + } + + /** + * Set whether to show SQL in the log (or in the console). + *

For more specific logging configuration, specify the appropriate + * vendor-specific settings as "jpaProperties". + * @see org.springframework.orm.jpa.AbstractEntityManagerFactoryBean#setJpaProperties + */ + public void setShowSql(boolean showSql) { + this.showSql = showSql; + } + + /** + * Return whether to show SQL in the log (or in the console). + */ + protected boolean isShowSql() { + return this.showSql; + } + + + public String getPersistenceProviderRootPackage() { + return null; + } + + public Map getJpaPropertyMap() { + return null; + } + + public JpaDialect getJpaDialect() { + return null; + } + + public Class getEntityManagerFactoryInterface() { + return EntityManagerFactory.class; + } + + public Class getEntityManagerInterface() { + return EntityManager.class; + } + + /** + * Post-process the EntityManagerFactory after it has been initialized. + * @param emf the EntityManagerFactory to process + */ + public void postProcessEntityManagerFactory(EntityManagerFactory emf) { + } + +} Index: 3rdParty_sources/spring/org/springframework/orm/jpa/vendor/Database.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/jpa/vendor/Database.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/orm/jpa/vendor/Database.java 17 Aug 2012 15:16:13 -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.orm.jpa.vendor; + +/** + * Enumeration for common database platforms. Allows strong typing of database type + * and portable configuration between JpaVendorDialect implementations. + * + *

If a given PersistenceProvider supports a database not listed here, + * the strategy class can still be specified using the fully-qualified class name. + * This enumeration is merely a convenience. The database products listed here + * are the same as those explicitly supported for Spring JDBC exception translation + * in sql-error-codes.xml. + * + * @author Rod Johnson + * @author Juergen Hoeller + * @since 2.0 + * @see AbstractJpaVendorAdapter#setDatabase + */ +public enum Database { + + DEFAULT, + + DB2, + + DERBY, + + H2, + + HSQL, + + INFORMIX, + + MYSQL, + + ORACLE, + + POSTGRESQL, + + SQL_SERVER, + + SYBASE + +} Index: 3rdParty_sources/spring/org/springframework/orm/jpa/vendor/EclipseLinkJpaDialect.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/jpa/vendor/EclipseLinkJpaDialect.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/orm/jpa/vendor/EclipseLinkJpaDialect.java 17 Aug 2012 15:16:13 -0000 1.1 @@ -0,0 +1,115 @@ +/* + * 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.vendor; + +import java.sql.Connection; +import java.sql.SQLException; + +import javax.persistence.EntityManager; +import javax.persistence.PersistenceException; + +import org.eclipse.persistence.internal.sessions.AbstractSession; +import org.eclipse.persistence.jpa.JpaEntityManager; +import org.eclipse.persistence.sessions.Session; +import org.eclipse.persistence.sessions.UnitOfWork; + +import org.springframework.jdbc.datasource.ConnectionHandle; +import org.springframework.jdbc.datasource.SimpleConnectionHandle; +import org.springframework.orm.jpa.DefaultJpaDialect; +import org.springframework.transaction.TransactionDefinition; +import org.springframework.transaction.TransactionException; + +/** + * {@link org.springframework.orm.jpa.JpaDialect} implementation for Eclipse + * Persistence Services (EclipseLink). Developed and tested against EclipseLink 1.0. + * + *

By default, this class acquires a EclipseLink transaction to get the JDBC Connection + * early. This allows mixing JDBC and JPA/EclipseLink operations in the same transaction. + * In some cases, this eager acquisition of a transaction/connection may impact + * scalability. In that case, set the "lazyDatabaseTransaction" flag to true if you + * do not require mixing JDBC and JPA operations in the same transaction. Otherwise, + * use a {@link org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy} + * to ensure that the cost of connection acquisition is near zero until code actually + * needs a JDBC Connection. + * + *

This class is very analogous to {@link TopLinkJpaDialect}, since + * EclipseLink is effectively the next generation of the TopLink product. + * Thanks to Mike Keith for the original EclipseLink support prototype! + * + * @author Juergen Hoeller + * @since 2.5.2 + * @see #setLazyDatabaseTransaction + * @see org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy + */ +public class EclipseLinkJpaDialect extends DefaultJpaDialect { + + private boolean lazyDatabaseTransaction = false; + + + /** + * Set whether to lazily start a database transaction within an + * EclipseLink transaction. + *

By default, database transactions are started early. This allows + * for reusing the same JDBC Connection throughout an entire transaction, + * including read operations, and also for exposing EclipseLink transactions + * to JDBC access code (working on the same DataSource). + *

It is only recommended to switch this flag to "true" when no JDBC access + * code is involved in any of the transactions, and when it is acceptable to + * perform read operations outside of the transactional JDBC Connection. + * @see oracle.toplink.sessions.UnitOfWork#beginEarlyTransaction() + */ + public void setLazyDatabaseTransaction(boolean lazyDatabaseTransaction) { + this.lazyDatabaseTransaction = lazyDatabaseTransaction; + } + + + @Override + public Object beginTransaction(EntityManager entityManager, TransactionDefinition definition) + throws PersistenceException, SQLException, TransactionException { + + super.beginTransaction(entityManager, definition); + if (!definition.isReadOnly() && !this.lazyDatabaseTransaction) { + // This is the magic bit. As with the existing Spring TopLink integration, + // begin an early transaction to force EclipseLink to get a JDBC Connection + // so that Spring can manage transactions with JDBC as well as EclipseLink. + UnitOfWork uow = (UnitOfWork) getSession(entityManager); + uow.beginEarlyTransaction(); + } + // Could return the UOW, if there were any advantage in having it later. + return null; + } + + @Override + public ConnectionHandle getJdbcConnection(EntityManager em, boolean readOnly) + throws PersistenceException, SQLException { + + AbstractSession session = (AbstractSession) getSession(em); + // The connection was already acquired eagerly in beginTransaction, + // unless lazyDatabaseTransaction was set to true. + Connection con = session.getAccessor().getConnection(); + return (con != null ? new SimpleConnectionHandle(con) : null); + } + + /** + * Get a traditional EclipseLink Session from the given EntityManager. + */ + protected Session getSession(EntityManager em) { + JpaEntityManager emi = (JpaEntityManager) em; + return emi.getActiveSession(); + } + +} Index: 3rdParty_sources/spring/org/springframework/orm/jpa/vendor/EclipseLinkJpaVendorAdapter.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/jpa/vendor/EclipseLinkJpaVendorAdapter.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/orm/jpa/vendor/EclipseLinkJpaVendorAdapter.java 17 Aug 2012 15:16:13 -0000 1.1 @@ -0,0 +1,117 @@ +/* + * 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.vendor; + +import java.util.Map; +import java.util.Properties; +import java.util.logging.Level; + +import javax.persistence.EntityManager; +import javax.persistence.spi.PersistenceProvider; + +import org.eclipse.persistence.config.PersistenceUnitProperties; +import org.eclipse.persistence.config.TargetDatabase; +import org.eclipse.persistence.jpa.JpaEntityManager; + +import org.springframework.orm.jpa.JpaDialect; + +/** + * {@link org.springframework.orm.jpa.JpaVendorAdapter} implementation for Eclipse + * Persistence Services (EclipseLink). Developed and tested against EclipseLink 1.0. + * + *

Exposes EclipseLink's persistence provider and EntityManager extension interface, + * and supports {@link AbstractJpaVendorAdapter}'s common configuration settings. + * + *

This class is very analogous to {@link TopLinkJpaVendorAdapter}, since + * EclipseLink is effectively the next generation of the TopLink product. + * Thanks to Mike Keith for the original EclipseLink support prototype! + * + * @author Juergen Hoeller + * @since 2.5.2 + * @see org.eclipse.persistence.jpa.PersistenceProvider + * @see org.eclipse.persistence.jpa.JpaEntityManager + */ +public class EclipseLinkJpaVendorAdapter extends AbstractJpaVendorAdapter { + + private final PersistenceProvider persistenceProvider = new org.eclipse.persistence.jpa.PersistenceProvider(); + + private final JpaDialect jpaDialect = new EclipseLinkJpaDialect(); + + + public PersistenceProvider getPersistenceProvider() { + return this.persistenceProvider; + } + + public String getPersistenceProviderRootPackage() { + return "org.eclipse.persistence"; + } + + public Map getJpaPropertyMap() { + Properties jpaProperties = new Properties(); + + if (getDatabasePlatform() != null) { + jpaProperties.setProperty(PersistenceUnitProperties.TARGET_DATABASE, getDatabasePlatform()); + } + else if (getDatabase() != null) { + String targetDatabase = determineTargetDatabaseName(getDatabase()); + if (targetDatabase != null) { + jpaProperties.setProperty(PersistenceUnitProperties.TARGET_DATABASE, targetDatabase); + } + } + + if (isGenerateDdl()) { + jpaProperties.setProperty(PersistenceUnitProperties.DDL_GENERATION, + PersistenceUnitProperties.CREATE_ONLY); + jpaProperties.setProperty(PersistenceUnitProperties.DDL_GENERATION_MODE, + PersistenceUnitProperties.DDL_DATABASE_GENERATION); + } + if (isShowSql()) { + jpaProperties.setProperty(PersistenceUnitProperties.LOGGING_LEVEL, Level.FINE.toString()); + } + + return jpaProperties; + } + + /** + * Determine the EclipseLink target database name for the given database. + * @param database the specified database + * @return the EclipseLink target database name, or null if none found + */ + protected String determineTargetDatabaseName(Database database) { + switch (database) { + case DB2: return TargetDatabase.DB2; + case DERBY: return TargetDatabase.Derby; + case HSQL: return TargetDatabase.HSQL; + case INFORMIX: return TargetDatabase.Informix; + case MYSQL: return TargetDatabase.MySQL4; + case ORACLE: return TargetDatabase.Oracle; + case POSTGRESQL: return TargetDatabase.PostgreSQL; + case SQL_SERVER: return TargetDatabase.SQLServer; + case SYBASE: return TargetDatabase.Sybase; + default: return null; + } + } + + public JpaDialect getJpaDialect() { + return this.jpaDialect; + } + + public Class getEntityManagerInterface() { + return JpaEntityManager.class; + } + +} Index: 3rdParty_sources/spring/org/springframework/orm/jpa/vendor/HibernateJpaDialect.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/jpa/vendor/HibernateJpaDialect.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/orm/jpa/vendor/HibernateJpaDialect.java 17 Aug 2012 15:16:13 -0000 1.1 @@ -0,0 +1,135 @@ +/* + * 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.vendor; + +import java.sql.Connection; +import java.sql.SQLException; + +import javax.persistence.EntityManager; +import javax.persistence.PersistenceException; + +import org.hibernate.FlushMode; +import org.hibernate.HibernateException; +import org.hibernate.Session; +import org.hibernate.ejb.HibernateEntityManager; + +import org.springframework.dao.DataAccessException; +import org.springframework.jdbc.datasource.ConnectionHandle; +import org.springframework.jdbc.datasource.SimpleConnectionHandle; +import org.springframework.orm.hibernate3.SessionFactoryUtils; +import org.springframework.orm.jpa.DefaultJpaDialect; +import org.springframework.orm.jpa.EntityManagerFactoryUtils; +import org.springframework.transaction.TransactionDefinition; +import org.springframework.transaction.TransactionException; + +/** + * {@link org.springframework.orm.jpa.JpaDialect} implementation for + * Hibernate EntityManager. Developed and tested against Hibernate 3.2. + * + * @author Costin Leau + * @author Juergen Hoeller + * @since 2.0 + */ +public class HibernateJpaDialect extends DefaultJpaDialect { + + public Object beginTransaction(EntityManager entityManager, TransactionDefinition definition) + throws PersistenceException, SQLException, TransactionException { + + super.beginTransaction(entityManager, definition); + return prepareTransaction(entityManager, definition.isReadOnly(), definition.getName()); + } + + public Object prepareTransaction(EntityManager entityManager, boolean readOnly, String name) + throws PersistenceException { + + Session session = getSession(entityManager); + FlushMode flushMode = session.getFlushMode(); + FlushMode previousFlushMode = null; + if (readOnly) { + // We should suppress flushing for a read-only transaction. + session.setFlushMode(FlushMode.MANUAL); + previousFlushMode = flushMode; + } + else { + // We need AUTO or COMMIT for a non-read-only transaction. + if (flushMode.lessThan(FlushMode.COMMIT)) { + session.setFlushMode(FlushMode.AUTO); + previousFlushMode = flushMode; + } + } + return new SessionTransactionData(session, previousFlushMode); + } + + public void cleanupTransaction(Object transactionData) { + ((SessionTransactionData) transactionData).resetFlushMode(); + } + + @Override + public ConnectionHandle getJdbcConnection(EntityManager entityManager, boolean readOnly) + throws PersistenceException, SQLException { + + Session session = getSession(entityManager); + Connection con = session.connection(); + return (con != null ? new SimpleConnectionHandle(con) : null); + } + + public DataAccessException translateExceptionIfPossible(RuntimeException ex) { + if (ex instanceof HibernateException) { + return SessionFactoryUtils.convertHibernateAccessException((HibernateException) ex); + } + if (ex instanceof PersistenceException && ex.getCause() instanceof HibernateException) { + return SessionFactoryUtils.convertHibernateAccessException((HibernateException) ex.getCause()); + } + return EntityManagerFactoryUtils.convertJpaAccessExceptionIfPossible(ex); + } + + protected Session getSession(EntityManager em) { + if (em instanceof HibernateEntityManager) { + return ((HibernateEntityManager) em).getSession(); + } + else { + Object delegate = em.getDelegate(); + if (delegate instanceof Session) { + return (Session) delegate; + } + else { + throw new IllegalStateException( + "Cannot obtain native Hibernate Session from given JPA EntityManager: " + em.getClass()); + } + } + } + + + private static class SessionTransactionData { + + private final Session session; + + private final FlushMode previousFlushMode; + + public SessionTransactionData(Session session, FlushMode previousFlushMode) { + this.session = session; + this.previousFlushMode = previousFlushMode; + } + + public void resetFlushMode() { + if (this.previousFlushMode != null) { + this.session.setFlushMode(this.previousFlushMode); + } + } + } + +} Index: 3rdParty_sources/spring/org/springframework/orm/jpa/vendor/HibernateJpaVendorAdapter.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/jpa/vendor/HibernateJpaVendorAdapter.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/orm/jpa/vendor/HibernateJpaVendorAdapter.java 17 Aug 2012 15:16:13 -0000 1.1 @@ -0,0 +1,127 @@ +/* + * 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.vendor; + +import java.util.Map; +import java.util.Properties; + +import javax.persistence.EntityManager; +import javax.persistence.EntityManagerFactory; +import javax.persistence.spi.PersistenceProvider; + +import org.hibernate.cfg.Environment; +import org.hibernate.dialect.DB2Dialect; +import org.hibernate.dialect.DerbyDialect; +import org.hibernate.dialect.H2Dialect; +import org.hibernate.dialect.HSQLDialect; +import org.hibernate.dialect.InformixDialect; +import org.hibernate.dialect.MySQLDialect; +import org.hibernate.dialect.Oracle9Dialect; +import org.hibernate.dialect.PostgreSQLDialect; +import org.hibernate.dialect.SQLServerDialect; +import org.hibernate.dialect.SybaseDialect; +import org.hibernate.ejb.HibernateEntityManager; +import org.hibernate.ejb.HibernateEntityManagerFactory; +import org.hibernate.ejb.HibernatePersistence; + +import org.springframework.orm.jpa.JpaDialect; + +/** + * {@link org.springframework.orm.jpa.JpaVendorAdapter} implementation for + * Hibernate EntityManager. Developed and tested against Hibernate 3.2. + * + *

Exposes Hibernate's persistence provider and EntityManager extension interface, + * and supports {@link AbstractJpaVendorAdapter}'s common configuration settings. + * + * @author Juergen Hoeller + * @author Rod Johnson + * @since 2.0 + * @see org.hibernate.ejb.HibernatePersistence + * @see org.hibernate.ejb.HibernateEntityManager + */ +public class HibernateJpaVendorAdapter extends AbstractJpaVendorAdapter { + + private final PersistenceProvider persistenceProvider = new HibernatePersistence(); + + private final JpaDialect jpaDialect = new HibernateJpaDialect(); + + + public PersistenceProvider getPersistenceProvider() { + return this.persistenceProvider; + } + + public String getPersistenceProviderRootPackage() { + return "org.hibernate"; + } + + public Map getJpaPropertyMap() { + Properties jpaProperties = new Properties(); + + if (getDatabasePlatform() != null) { + jpaProperties.setProperty(Environment.DIALECT, getDatabasePlatform()); + } + else if (getDatabase() != null) { + Class databaseDialectClass = determineDatabaseDialectClass(getDatabase()); + if (databaseDialectClass != null) { + jpaProperties.setProperty(Environment.DIALECT, databaseDialectClass.getName()); + } + } + + if (isGenerateDdl()) { + jpaProperties.setProperty(Environment.HBM2DDL_AUTO, "update"); + } + if (isShowSql()) { + jpaProperties.setProperty(Environment.SHOW_SQL, "true"); + } + + return jpaProperties; + } + + /** + * Determine the Hibernate database dialect class for the given target database. + * @param database the target database + * @return the Hibernate database dialect class, or null if none found + */ + protected Class determineDatabaseDialectClass(Database database) { + switch (database) { + case DB2: return DB2Dialect.class; + case DERBY: return DerbyDialect.class; + case H2: return H2Dialect.class; + case HSQL: return HSQLDialect.class; + case INFORMIX: return InformixDialect.class; + case MYSQL: return MySQLDialect.class; + case ORACLE: return Oracle9Dialect.class; // deprecated since Hibernate 3.2.5 - to be updated in Spring 3.0 + case POSTGRESQL: return PostgreSQLDialect.class; + case SQL_SERVER: return SQLServerDialect.class; + case SYBASE: return SybaseDialect.class; + default: return null; + } + } + + public JpaDialect getJpaDialect() { + return this.jpaDialect; + } + + public Class getEntityManagerFactoryInterface() { + return HibernateEntityManagerFactory.class; + } + + public Class getEntityManagerInterface() { + return HibernateEntityManager.class; + } + +} Index: 3rdParty_sources/spring/org/springframework/orm/jpa/vendor/OpenJpaDialect.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/jpa/vendor/OpenJpaDialect.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/orm/jpa/vendor/OpenJpaDialect.java 17 Aug 2012 15:16:13 -0000 1.1 @@ -0,0 +1,132 @@ +/* + * 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.vendor; + +import java.sql.Connection; +import java.sql.SQLException; + +import javax.persistence.EntityManager; +import javax.persistence.PersistenceException; + +import org.apache.openjpa.persistence.OpenJPAEntityManager; +import org.apache.openjpa.persistence.OpenJPAPersistence; + +import org.springframework.jdbc.datasource.ConnectionHandle; +import org.springframework.jdbc.datasource.ConnectionHolder; +import org.springframework.jdbc.support.JdbcUtils; +import org.springframework.orm.jpa.DefaultJpaDialect; +import org.springframework.transaction.SavepointManager; +import org.springframework.transaction.TransactionDefinition; +import org.springframework.transaction.TransactionException; + +/** + * {@link org.springframework.orm.jpa.JpaDialect} implementation for + * Apache OpenJPA. Developed and tested against OpenJPA 0.9.7. + * + * @author Costin Leau + * @author Juergen Hoeller + * @since 2.0 + */ +public class OpenJpaDialect extends DefaultJpaDialect { + + @Override + public Object beginTransaction(EntityManager entityManager, TransactionDefinition definition) + throws PersistenceException, SQLException, TransactionException { + + super.beginTransaction(entityManager, definition); + OpenJPAEntityManager em = getOpenJPAEntityManager(entityManager); + if (!definition.isReadOnly()) { + // Like with TopLink, make sure to start the logic transaction early so that other + // participants using the connection (such as JdbcTemplate) run in a transaction. + em.beginStore(); + } + return new OpenJpaTransactionData(em); + } + + @Override + public ConnectionHandle getJdbcConnection(EntityManager entityManager, boolean readOnly) + throws PersistenceException, SQLException { + + return new OpenJpaConnectionHandle(getOpenJPAEntityManager(entityManager)); + } + + /** + * Return the OpenJPA-specific interface of EntityManager. + * @param em the generic EntityManager instance + * @return the OpenJPA-specific interface of EntityManager + */ + protected OpenJPAEntityManager getOpenJPAEntityManager(EntityManager em) { + return OpenJPAPersistence.cast(em); + } + + + /** + * Transaction data Object exposed from beginTransaction, + * implementing the SavepointManager interface. + */ + private static class OpenJpaTransactionData implements SavepointManager { + + private final OpenJPAEntityManager entityManager; + + private int savepointCounter = 0; + + public OpenJpaTransactionData(OpenJPAEntityManager entityManager) { + this.entityManager = entityManager; + } + + public Object createSavepoint() throws TransactionException { + this.savepointCounter++; + String savepointName = ConnectionHolder.SAVEPOINT_NAME_PREFIX + this.savepointCounter; + this.entityManager.setSavepoint(savepointName); + return savepointName; + } + + public void rollbackToSavepoint(Object savepoint) throws TransactionException { + this.entityManager.rollbackToSavepoint((String) savepoint); + } + + public void releaseSavepoint(Object savepoint) throws TransactionException { + this.entityManager.releaseSavepoint((String) savepoint); + } + } + + + /** + * ConnectionHandle implementation that fetches a new OpenJPA-provided Connection + * for every getConnection call and closes the Connection on + * releaseConnection. This is necessary because OpenJPA requires the + * fetched Connection to be closed before continuing EntityManager work. + * @see org.apache.openjpa.persistence.OpenJPAEntityManager#getConnection() + */ + private static class OpenJpaConnectionHandle implements ConnectionHandle { + + private final OpenJPAEntityManager entityManager; + + public OpenJpaConnectionHandle(OpenJPAEntityManager entityManager) { + this.entityManager = entityManager; + } + + public Connection getConnection() { + return (Connection) this.entityManager.getConnection(); + } + + public void releaseConnection(Connection con) { + JdbcUtils.closeConnection(con); + } + } + +} Index: 3rdParty_sources/spring/org/springframework/orm/jpa/vendor/OpenJpaVendorAdapter.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/jpa/vendor/OpenJpaVendorAdapter.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/orm/jpa/vendor/OpenJpaVendorAdapter.java 17 Aug 2012 15:16:13 -0000 1.1 @@ -0,0 +1,117 @@ +/* + * 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.vendor; + +import java.util.Map; +import java.util.Properties; + +import javax.persistence.EntityManager; +import javax.persistence.EntityManagerFactory; +import javax.persistence.spi.PersistenceProvider; + +import org.apache.openjpa.persistence.OpenJPAEntityManagerFactorySPI; +import org.apache.openjpa.persistence.OpenJPAEntityManagerSPI; +import org.apache.openjpa.persistence.PersistenceProviderImpl; + +import org.springframework.orm.jpa.JpaDialect; + +/** + * {@link org.springframework.orm.jpa.JpaVendorAdapter} implementation for + * Apache OpenJPA. Developed and tested against OpenJPA 1.0.0. + * + *

Exposes OpenJPA's persistence provider and EntityManager extension interface, + * and supports {@link AbstractJpaVendorAdapter}'s common configuration settings. + * + * @author Costin Leau + * @author Juergen Hoeller + * @since 2.0 + * @see org.apache.openjpa.persistence.PersistenceProviderImpl + * @see org.apache.openjpa.persistence.OpenJPAEntityManager + */ +public class OpenJpaVendorAdapter extends AbstractJpaVendorAdapter { + + private final PersistenceProvider persistenceProvider = new PersistenceProviderImpl(); + + private final OpenJpaDialect jpaDialect = new OpenJpaDialect(); + + + public PersistenceProvider getPersistenceProvider() { + return this.persistenceProvider; + } + + public String getPersistenceProviderRootPackage() { + return "org.apache.openjpa"; + } + + public Map getJpaPropertyMap() { + Properties jpaProperties = new Properties(); + + if (getDatabasePlatform() != null) { + jpaProperties.setProperty("openjpa.jdbc.DBDictionary", getDatabasePlatform()); + } + else if (getDatabase() != null) { + String databaseDictonary = determineDatabaseDictionary(getDatabase()); + if (databaseDictonary != null) { + jpaProperties.setProperty("openjpa.jdbc.DBDictionary", databaseDictonary); + } + } + + if (isGenerateDdl()) { + jpaProperties.setProperty("openjpa.jdbc.SynchronizeMappings", "buildSchema(ForeignKeys=true)"); + } + + if (isShowSql()) { + // Taken from the OpenJPA 0.9.6 docs ("Standard OpenJPA Log Configuration + All SQL Statements") + jpaProperties.setProperty("openjpa.Log", "DefaultLevel=WARN, Runtime=INFO, Tool=INFO, SQL=TRACE"); + } + + return jpaProperties; + } + + /** + * Determine the OpenJPA database dictionary name for the given database. + * @param database the specified database + * @return the OpenJPA database dictionary name, or null if none found + */ + protected String determineDatabaseDictionary(Database database) { + switch (database) { + case DB2: return "db2"; + case DERBY: return "derby"; + case HSQL: return "hsql(SimulateLocking=true)"; + case INFORMIX: return "informix"; + case MYSQL: return "mysql"; + case ORACLE: return "oracle"; + case POSTGRESQL: return "postgres"; + case SQL_SERVER: return "sqlserver"; + case SYBASE: return "sybase"; + default: return null; + } + } + + public JpaDialect getJpaDialect() { + return this.jpaDialect; + } + + public Class getEntityManagerFactoryInterface() { + return OpenJPAEntityManagerFactorySPI.class; + } + + public Class getEntityManagerInterface() { + return OpenJPAEntityManagerSPI.class; + } + +} Index: 3rdParty_sources/spring/org/springframework/orm/jpa/vendor/TopLinkJpaDialect.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/jpa/vendor/TopLinkJpaDialect.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/orm/jpa/vendor/TopLinkJpaDialect.java 17 Aug 2012 15:16:13 -0000 1.1 @@ -0,0 +1,111 @@ +/* + * 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.vendor; + +import java.sql.Connection; +import java.sql.SQLException; + +import javax.persistence.EntityManager; +import javax.persistence.PersistenceException; + +import oracle.toplink.essentials.internal.sessions.AbstractSession; +import oracle.toplink.essentials.sessions.Session; +import oracle.toplink.essentials.sessions.UnitOfWork; + +import org.springframework.jdbc.datasource.ConnectionHandle; +import org.springframework.jdbc.datasource.SimpleConnectionHandle; +import org.springframework.orm.jpa.DefaultJpaDialect; +import org.springframework.transaction.TransactionDefinition; +import org.springframework.transaction.TransactionException; + +/** + * {@link org.springframework.orm.jpa.JpaDialect} implementation for + * Oracle TopLink Essentials. Developed and tested against TopLink Essentials v2. + * + *

By default, this class acquires a TopLink transaction to get the JDBC Connection + * early. This allows mixing JDBC and JPA/TopLink operations in the same transaction. + * In some cases, this eager acquisition of a transaction/connection may impact + * scalability. In that case, set the "lazyDatabaseTransaction" flag to true if you + * do not require mixing JDBC and JPA operations in the same transaction. Otherwise, + * use a {@link org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy} + * to ensure that the cost of connection acquisition is near zero until code actually + * needs a JDBC Connection. + * + * @author Rod Johnson + * @author Juergen Hoeller + * @since 2.0 + * @see #setLazyDatabaseTransaction + * @see org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy + */ +public class TopLinkJpaDialect extends DefaultJpaDialect { + + private boolean lazyDatabaseTransaction = false; + + + /** + * Set whether to lazily start a database transaction within a TopLink + * transaction. + *

By default, database transactions are started early. This allows + * for reusing the same JDBC Connection throughout an entire transaction, + * including read operations, and also for exposing TopLink transactions + * to JDBC access code (working on the same DataSource). + *

It is only recommended to switch this flag to "true" when no JDBC access + * code is involved in any of the transactions, and when it is acceptable to + * perform read operations outside of the transactional JDBC Connection. + * @see oracle.toplink.sessions.UnitOfWork#beginEarlyTransaction() + */ + public void setLazyDatabaseTransaction(boolean lazyDatabaseTransaction) { + this.lazyDatabaseTransaction = lazyDatabaseTransaction; + } + + + @Override + public Object beginTransaction(EntityManager entityManager, TransactionDefinition definition) + throws PersistenceException, SQLException, TransactionException { + + super.beginTransaction(entityManager, definition); + if (!definition.isReadOnly() && !this.lazyDatabaseTransaction) { + // This is the magic bit. As with the existing Spring TopLink integration, + // begin an early transaction to force TopLink to get a JDBC Connection + // so that Spring can manage transactions with JDBC as well as TopLink. + UnitOfWork uow = (UnitOfWork) getSession(entityManager); + uow.beginEarlyTransaction(); + } + // Could return the UOW, if there were any advantage in having it later. + return null; + } + + @Override + public ConnectionHandle getJdbcConnection(EntityManager em, boolean readOnly) + throws PersistenceException, SQLException { + + AbstractSession session = (AbstractSession) getSession(em); + // The connection was already acquired eagerly in beginTransaction, + // unless lazyDatabaseTransaction was set to true. + Connection con = session.getAccessor().getConnection(); + return (con != null ? new SimpleConnectionHandle(con) : null); + } + + /** + * Get a traditional TopLink Session from the given EntityManager. + */ + protected Session getSession(EntityManager em) { + oracle.toplink.essentials.ejb.cmp3.EntityManager emi = (oracle.toplink.essentials.ejb.cmp3.EntityManager) em; + return emi.getActiveSession(); + } + +} Index: 3rdParty_sources/spring/org/springframework/orm/jpa/vendor/TopLinkJpaVendorAdapter.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/jpa/vendor/TopLinkJpaVendorAdapter.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/orm/jpa/vendor/TopLinkJpaVendorAdapter.java 17 Aug 2012 15:16:13 -0000 1.1 @@ -0,0 +1,114 @@ +/* + * 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.vendor; + +import java.util.Map; +import java.util.Properties; +import java.util.logging.Level; + +import javax.persistence.EntityManager; +import javax.persistence.spi.PersistenceProvider; + +import oracle.toplink.essentials.config.TargetDatabase; +import oracle.toplink.essentials.config.TopLinkProperties; +import oracle.toplink.essentials.ejb.cmp3.EntityManagerFactoryProvider; + +import org.springframework.orm.jpa.JpaDialect; + +/** + * {@link org.springframework.orm.jpa.JpaVendorAdapter} implementation for + * Oracle TopLink Essentials. Developed and tested against TopLink Essentials v2. + * + *

Exposes TopLink's persistence provider and EntityManager extension interface, + * and supports {@link AbstractJpaVendorAdapter}'s common configuration settings. + * + * @author Rod Johnson + * @author Juergen Hoeller + * @since 2.0 + * @see oracle.toplink.essentials.ejb.cmp3.EntityManagerFactoryProvider + * @see oracle.toplink.essentials.ejb.cmp3.EntityManager + */ +public class TopLinkJpaVendorAdapter extends AbstractJpaVendorAdapter { + + private final PersistenceProvider persistenceProvider = new EntityManagerFactoryProvider(); + + private final JpaDialect jpaDialect = new TopLinkJpaDialect(); + + + public PersistenceProvider getPersistenceProvider() { + return this.persistenceProvider; + } + + public String getPersistenceProviderRootPackage() { + return "oracle.toplink.essentials"; + } + + public Map getJpaPropertyMap() { + Properties jpaProperties = new Properties(); + + if (getDatabasePlatform() != null) { + jpaProperties.setProperty(TopLinkProperties.TARGET_DATABASE, getDatabasePlatform()); + } + else if (getDatabase() != null) { + String targetDatabase = determineTargetDatabaseName(getDatabase()); + if (targetDatabase != null) { + jpaProperties.setProperty(TopLinkProperties.TARGET_DATABASE, targetDatabase); + } + } + + if (isGenerateDdl()) { + jpaProperties.setProperty(EntityManagerFactoryProvider.DDL_GENERATION, + EntityManagerFactoryProvider.CREATE_ONLY); + jpaProperties.setProperty(EntityManagerFactoryProvider.DDL_GENERATION_MODE, + EntityManagerFactoryProvider.DDL_DATABASE_GENERATION); + } + if (isShowSql()) { + jpaProperties.setProperty(TopLinkProperties.LOGGING_LEVEL, Level.FINE.toString()); + } + + return jpaProperties; + } + + /** + * Determine the TopLink target database name for the given database. + * @param database the specified database + * @return the TopLink target database name, or null if none found + */ + protected String determineTargetDatabaseName(Database database) { + switch (database) { + case DB2: return TargetDatabase.DB2; + case DERBY: return TargetDatabase.Derby; + case HSQL: return TargetDatabase.HSQL; + case INFORMIX: return TargetDatabase.Informix; + case MYSQL: return TargetDatabase.MySQL4; + case ORACLE: return TargetDatabase.Oracle; + case POSTGRESQL: return TargetDatabase.PostgreSQL; + case SQL_SERVER: return TargetDatabase.SQLServer; + case SYBASE: return TargetDatabase.Sybase; + default: return null; + } + } + + public JpaDialect getJpaDialect() { + return this.jpaDialect; + } + + public Class getEntityManagerInterface() { + return oracle.toplink.essentials.ejb.cmp3.EntityManager.class; + } + +} Index: 3rdParty_sources/spring/org/springframework/orm/jpa/vendor/package.html =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/jpa/vendor/package.html,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/orm/jpa/vendor/package.html 17 Aug 2012 15:16:13 -0000 1.1 @@ -0,0 +1,7 @@ + + + +Support classes for adapting to specific JPA vendors. + + + Index: 3rdParty_sources/spring/org/springframework/orm/toplink/AbstractSessionFactory.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/toplink/AbstractSessionFactory.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/orm/toplink/AbstractSessionFactory.java 17 Aug 2012 15:16:11 -0000 1.1 @@ -0,0 +1,221 @@ +/* + * 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.toplink; + +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; + +import oracle.toplink.exceptions.TopLinkException; +import oracle.toplink.sessions.Session; +import oracle.toplink.sessions.UnitOfWork; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * Abstract SessionFactory implementation that creates proxies for + * "managed" client Sessions and transaction-aware Session references. + * + *

Delegates to two template methods: + * + * @author Juergen Hoeller + * @since 1.2.6 + * @see #getMasterSession() + * @see #createClientSession() + */ +public abstract class AbstractSessionFactory implements SessionFactory { + + /** Logger available to subclasses */ + protected final Log logger = LogFactory.getLog(getClass()); + + + /** + * Create a plain client Session for this factory's master Session. + * @see #createClientSession() + */ + public Session createSession() throws TopLinkException { + logger.debug("Creating TopLink client Session"); + return createClientSession(); + } + + /** + * Create a "managed" client Session reference for an underlying + * client Session created for this factory. + * @see #createClientSession() + */ + public Session createManagedClientSession() throws TopLinkException { + logger.debug("Creating managed TopLink client Session"); + Session target = createClientSession(); + return (Session) Proxy.newProxyInstance(target.getClass().getClassLoader(), + new Class[] {Session.class}, new ManagedClientInvocationHandler(target)); + } + + /** + * Create a transaction-aware Session reference for this factory's master Session, + * expecting transactions to be registered for this SessionFactory. + * @see #getMasterSession() + * @see oracle.toplink.sessions.Session#getActiveSession() + * @see oracle.toplink.sessions.Session#getActiveUnitOfWork() + */ + public Session createTransactionAwareSession() throws TopLinkException { + logger.debug("Creating transaction-aware TopLink Session"); + return createTransactionAwareSession(this); + } + + /** + * Create a transaction-aware Session reference for this factory's master Session, + * expecting transactions to be registered for the given SessionFactory. + *

This method is public to allow custom SessionFactory facades to access + * it directly, if necessary. + * @param sessionFactory the SessionFactory that transactions + * are expected to be registered for + * @see #getMasterSession() + * @see oracle.toplink.sessions.Session#getActiveSession() + * @see oracle.toplink.sessions.Session#getActiveUnitOfWork() + */ + public Session createTransactionAwareSession(SessionFactory sessionFactory) throws TopLinkException { + Session target = getMasterSession(); + return (Session) Proxy.newProxyInstance( + target.getClass().getClassLoader(), new Class[] {Session.class}, + new TransactionAwareInvocationHandler(sessionFactory, target)); + } + + + /** + * Return this factory's "master" Session. + * For example, a TopLink ServerSession. + *

Used for creating transaction-aware Session reference. + */ + protected abstract Session getMasterSession(); + + /** + * Create a new client Session for this factory's master Session. + * For example, a TopLink ClientSession. + *

Used for creating plain Sessions and "managed" client Sessions. + * @throws TopLinkException if creation of a client Session failed + */ + protected abstract Session createClientSession() throws TopLinkException; + + + /** + * Invocation handler that decorates a client Session with an "active" + * UnitOfWork. For use in situations where Spring's TopLinkTransactionManager + * requires a "managed" thread-safe TopLink Session. + */ + private static class ManagedClientInvocationHandler implements InvocationHandler { + + private final Session target; + + private final UnitOfWork uow; + + public ManagedClientInvocationHandler(Session target) { + this.target = target; + this.uow = this.target.acquireUnitOfWork(); + } + + 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 SessionFactory proxy. + return new Integer(System.identityHashCode(proxy)); + } + else if (method.getName().equals("getActiveSession")) { + return this.target; + } + else if (method.getName().equals("getActiveUnitOfWork")) { + return this.uow; + } + else if (method.getName().equals("release")) { + this.uow.release(); + this.target.release(); + } + + // Invoke method on target Session. + try { + return method.invoke(this.target, args); + } + catch (InvocationTargetException ex) { + throw ex.getTargetException(); + } + } + } + + + /** + * Invocation handler that delegates getActiveSession calls + * to SessionFactoryUtils, for being aware of thread-bound transactions. + */ + private static class TransactionAwareInvocationHandler implements InvocationHandler { + + private final SessionFactory sessionFactory; + + private final Session target; + + public TransactionAwareInvocationHandler(SessionFactory sessionFactory, Session target) { + this.sessionFactory = sessionFactory; + 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 SessionFactory proxy. + return new Integer(System.identityHashCode(proxy)); + } + else if (method.getName().equals("getActiveSession")) { + // Handle getActiveSession method: return transactional Session, if any. + try { + return SessionFactoryUtils.doGetSession(this.sessionFactory, false); + } + catch (IllegalStateException ex) { + // getActiveSession is supposed to return the Session itself if no active one found. + return this.target; + } + } + else if (method.getName().equals("getActiveUnitOfWork")) { + // Handle getActiveUnitOfWork method: return transactional UnitOfWork, if any. + try { + return SessionFactoryUtils.doGetSession(this.sessionFactory, false).getActiveUnitOfWork(); + } + catch (IllegalStateException ex) { + // getActiveUnitOfWork is supposed to return null if no active one found. + return null; + } + } + + // Invoke method on target Session. + try { + return method.invoke(this.target, args); + } + catch (InvocationTargetException ex) { + throw ex.getTargetException(); + } + } + } + +} Index: 3rdParty_sources/spring/org/springframework/orm/toplink/LocalSessionFactory.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/toplink/LocalSessionFactory.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/orm/toplink/LocalSessionFactory.java 17 Aug 2012 15:16:11 -0000 1.1 @@ -0,0 +1,458 @@ +/* + * 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.toplink; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; + +import javax.sql.DataSource; + +import oracle.toplink.exceptions.TopLinkException; +import oracle.toplink.internal.databaseaccess.DatabasePlatform; +import oracle.toplink.jndi.JNDIConnector; +import oracle.toplink.sessionbroker.SessionBroker; +import oracle.toplink.sessions.DatabaseLogin; +import oracle.toplink.sessions.DatabaseSession; +import oracle.toplink.sessions.SessionLog; +import oracle.toplink.threetier.ServerSession; +import oracle.toplink.tools.sessionconfiguration.XMLLoader; +import oracle.toplink.tools.sessionmanagement.SessionManager; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import org.springframework.beans.PropertyAccessorFactory; +import org.springframework.util.ClassUtils; +import org.springframework.util.CollectionUtils; +import org.springframework.util.ReflectionUtils; + +/** + * Convenient JavaBean-style factory for a TopLink SessionFactory instance. + * Loads a TopLink sessions.xml file from the class path, exposing a + * specific TopLink Session defined there (usually a ServerSession). + * + *

TopLink Session configuration is done using a sessions.xml file. + * The most convenient way to create the sessions.xml file is to use + * the Oracle TopLink SessionsEditor workbench. The sessions.xml file + * contains all runtime configuration and points to a second XML or Class resource + * from which to load the actual TopLink project metadata (which defines mappings). + * + *

LocalSessionFactory loads the sessions.xml file during + * initialization in order to bootstrap the specified TopLink (Server)Session. + * The name of the actual config resource and the name of the Session to be loaded, + * if different from sessions.xml and "Session", respectively, can be + * configured through bean properties. + * + *

All resources (sessions.xml and Mapping Workbench metadata) are + * loaded using ClassLoader.getResourceAsStream calls by TopLink, so + * users may need to configure a ClassLoader with appropriate visibility. This is + * particularly important in J2EE environments where the TopLink metadata might be + * deployed to a different location than the Spring configuration. The ClassLoader + * used to search for the TopLink metadata and to load the persistent classes + * defined there will default to the the context ClassLoader for the current Thread. + * + *

TopLink's debug logging can be redirected to Commons Logging by passing a + * CommonsLoggingSessionLog to the "sessionLog" bean property. Otherwise, TopLink + * uses it's own DefaultSessionLog, whose levels are configured in the + * sessions.xml file. + * + *

This class has been tested against both TopLink 9.0.4 and TopLink 10.1.3. + * It will automatically adapt to the TopLink version encountered: for example, + * using an XMLSessionConfigLoader on 10.1.3, but an XMLLoader on 9.0.4. + * + *

NOTE: When defining a TopLink SessionFactory in a Spring application + * context, you will usually define a bean of type LocalSessionFactoryBean. + * LocalSessionFactoryBean is a subclass of this factory, which will automatically + * expose the created TopLink SessionFactory instance as bean reference. + * + * @author Juergen Hoeller + * @author James Clark + * @since 1.2 + * @see LocalSessionFactoryBean + * @see TopLinkTemplate#setSessionFactory + * @see TopLinkTransactionManager#setSessionFactory + * @see SingleSessionFactory + * @see ServerSessionFactory + * @see oracle.toplink.threetier.ServerSession + * @see oracle.toplink.tools.sessionconfiguration.XMLLoader + * @see oracle.toplink.tools.sessionconfiguration.XMLSessionConfigLoader + */ +public class LocalSessionFactory { + + /** + * The default location of the sessions.xml TopLink configuration file: + * "sessions.xml" in the class path. + */ + public static final String DEFAULT_SESSIONS_XML = "sessions.xml"; + + /** + * The default session name to look for in the sessions.xml: "Session". + */ + public static final String DEFAULT_SESSION_NAME = "Session"; + + + protected final Log logger = LogFactory.getLog(getClass()); + + /** + * The classpath location of the sessions TopLink configuration file. + */ + private String configLocation = DEFAULT_SESSIONS_XML; + + /** + * The session name to look for in the sessions.xml configuration file. + */ + private String sessionName = DEFAULT_SESSION_NAME; + + /** + * The ClassLoader to use to load the sessions.xml and project XML files. + */ + private ClassLoader sessionClassLoader; + + private DatabaseLogin databaseLogin; + + private final Map loginPropertyMap = new HashMap(); + + private DataSource dataSource; + + private DatabasePlatform databasePlatform; + + private SessionLog sessionLog; + + + /** + * Set the TopLink sessions.xml configuration file that defines + * TopLink Sessions, as class path resource location. + *

The sessions.xml file will usually be placed in the META-INF + * directory or root path of a JAR file, or the WEB-INF/classes + * directory of a WAR file (specifying "META-INF/toplink-sessions.xml" or + * simply "toplink-sessions.xml" as config location, respectively). + *

The default config location is "sessions.xml" in the root of the class path. + * @param configLocation the class path location of the sessions.xml file + */ + public void setConfigLocation(String configLocation) { + this.configLocation = configLocation; + } + + /** + * Set the name of the TopLink Session, as defined in TopLink's + * sessions.xml configuration file. + * The default session name is "Session". + */ + public void setSessionName(String sessionName) { + this.sessionName = sessionName; + } + + /** + * Set the ClassLoader that should be used to lookup the config resources. + * If nothing is set here, then we will try to use the Thread context ClassLoader + * and the ClassLoader that loaded this factory class, in that order. + *

This ClassLoader will be used to load the TopLink configuration files + * and the project metadata. Furthermore, the TopLink ConversionManager will + * use this ClassLoader to load all TopLink entity classes. If the latter is not + * appropriate, users can configure a pre-login SessionEvent to alter the + * ConversionManager ClassLoader that TopLink will use at runtime. + */ + public void setSessionClassLoader(ClassLoader sessionClassLoader) { + this.sessionClassLoader = sessionClassLoader; + } + + /** + * Specify the DatabaseLogin instance that carries the TopLink database + * configuration to use. This is an alternative to specifying that information + * in a <login> tag in the sessions.xml configuration file, + * allowing for configuring a DatabaseLogin instance as standard Spring bean + * definition (being able to leverage Spring's placeholder mechanism, etc). + *

The DatabaseLogin instance can either carry traditional JDBC config properties + * or hold a nested TopLink Connector instance, pointing to the connection pool to use. + * DatabaseLogin also holds the TopLink DatabasePlatform instance that defines the + * database product that TopLink is talking to (for example, HSQLPlatform). + *

WARNING: Overriding the Login instance has been reported to not + * work on TopLink 10.1.3.0 and 10.1.3.1. Specify {@link #setLoginProperties + * "loginProperties"} or {@link #getLoginPropertyMap "loginPropertyMap[...]"} + * entries instead, if you prefer to have the login configuration defined + * on the Spring LocalSessionFactory. + */ + public void setDatabaseLogin(DatabaseLogin databaseLogin) { + this.databaseLogin = databaseLogin; + } + + /** + * Specify TopLink login properties, to be passed to + * the {@link oracle.toplink.sessions.DatabaseLogin} instance. + *

Can be populated with a String "value" (parsed via PropertiesEditor) + * or a "props" element in XML bean definitions. + * @see oracle.toplink.sessions.DatabaseLogin + */ + public void setLoginProperties(Properties loginProperties) { + CollectionUtils.mergePropertiesIntoMap(loginProperties, this.loginPropertyMap); + } + + /** + * Specify TopLink login properties as a Map, to be passed to + * the {@link oracle.toplink.sessions.DatabaseLogin} instance. + *

Can be populated with a "map" or "props" element in XML bean definitions. + * @see oracle.toplink.sessions.DatabaseLogin + */ + public void setLoginPropertyMap(Map loginProperties) { + if (loginProperties != null) { + this.loginPropertyMap.putAll(loginProperties); + } + } + + /** + * Allow Map access to the TopLink login properties to be passed to the + * DatabaseLogin instance, with the option to add or override specific entries. + *

Useful for specifying entries directly, for example via + * "loginPropertyMap[tableQualifier]". + * @see oracle.toplink.sessions.DatabaseLogin + */ + public Map getLoginPropertyMap() { + return this.loginPropertyMap; + } + + /** + * Specify a standard JDBC DataSource that TopLink should use as connection pool. + * This allows for using a shared DataSource definition instead of TopLink's + * own connection pool. + *

A passed-in DataSource will be wrapped in an appropriate TopLink Connector + * and registered with the TopLink DatabaseLogin instance (either the default + * instance or one passed in through the "databaseLogin" property). The + * "usesExternalConnectionPooling" flag will automatically be set to "true". + * @see oracle.toplink.sessions.DatabaseLogin#setConnector(oracle.toplink.sessions.Connector) + * @see oracle.toplink.sessions.DatabaseLogin#setUsesExternalConnectionPooling(boolean) + * @see #setDatabaseLogin(oracle.toplink.sessions.DatabaseLogin) + */ + public void setDataSource(DataSource dataSource) { + this.dataSource = dataSource; + } + + /** + * Specify the TopLink DatabasePlatform instance that the Session should use: + * for example, HSQLPlatform. This is an alternative to specifying the platform + * in a <login> tag in the sessions.xml configuration file. + *

A passed-in DatabasePlatform will be registered with the TopLink + * DatabaseLogin instance (either the default instance or one passed in + * through the "databaseLogin" property). + * @see oracle.toplink.internal.databaseaccess.HSQLPlatform + * @see oracle.toplink.platform.database.HSQLPlatform + */ + public void setDatabasePlatform(DatabasePlatform databasePlatform) { + this.databasePlatform = databasePlatform; + } + + /** + * Specify a TopLink SessionLog instance to use for detailed logging of the + * Session's activities: for example, DefaultSessionLog (which logs to the + * console), JavaLog (which logs through JDK 1.4'S java.util.logging, + * available as of TopLink 10.1.3), or CommonsLoggingSessionLog / + * CommonsLoggingSessionLog904 (which logs through Commons Logging, + * on TopLink 10.1.3 and 9.0.4, respectively). + *

Note that detailed Session logging is usually only useful for debug + * logging, with adjustable detail level. As of TopLink 10.1.3, TopLink also + * uses different log categories, which allows for fine-grained filtering of + * log messages. For standard execution, no SessionLog needs to be specified. + * @see oracle.toplink.sessions.DefaultSessionLog + * @see oracle.toplink.logging.DefaultSessionLog + * @see oracle.toplink.logging.JavaLog + * @see org.springframework.orm.toplink.support.CommonsLoggingSessionLog + * @see org.springframework.orm.toplink.support.CommonsLoggingSessionLog904 + */ + public void setSessionLog(SessionLog sessionLog) { + this.sessionLog = sessionLog; + } + + + /** + * Create a TopLink SessionFactory according to the configuration settings. + * @return the new TopLink SessionFactory + * @throws TopLinkException in case of errors + */ + public SessionFactory createSessionFactory() throws TopLinkException { + if (logger.isInfoEnabled()) { + logger.info("Initializing TopLink SessionFactory from [" + this.configLocation + "]"); + } + + // Determine class loader to use. + ClassLoader classLoader = + (this.sessionClassLoader != null ? this.sessionClassLoader : ClassUtils.getDefaultClassLoader()); + + // Initialize the TopLink Session, using the configuration file + // and the session name. + DatabaseSession session = loadDatabaseSession(this.configLocation, this.sessionName, classLoader); + + // It is possible for SessionManager to return a null Session! + if (session == null) { + throw new IllegalStateException( + "A session named '" + this.sessionName + "' could not be loaded from resource [" + + this.configLocation + "] using ClassLoader [" + classLoader + "]. " + + "This is most likely a deployment issue: Can the class loader access the resource?"); + } + + DatabaseLogin login = (this.databaseLogin != null ? this.databaseLogin : session.getLogin()); + + // Apply specified login properties to the DatabaseLogin instance. + if (this.loginPropertyMap != null) { + PropertyAccessorFactory.forBeanPropertyAccess(login).setPropertyValues(this.loginPropertyMap); + } + + // Override default connection pool with specified DataSource, if any. + if (this.dataSource != null) { + login.setConnector(new JNDIConnector(this.dataSource)); + login.setUsesExternalConnectionPooling(true); + } + + // Override default DatabasePlatform with specified one, if any. + if (this.databasePlatform != null) { + login.usePlatform(this.databasePlatform); + } + + // Override default DatabaseLogin instance with specified one, if any. + if (this.databaseLogin != null) { + setDatabaseLogin(session, this.databaseLogin); + } + + // Override default SessionLog with specified one, if any. + if (this.sessionLog != null) { + session.setSessionLog(this.sessionLog); + session.logMessages(); + } + + // Log in and create corresponding SessionFactory. + session.login(); + return newSessionFactory(session); + } + + /** + * Handle differences between the Session.setLogin interface + * between TopLink 9.0.4 to 10.1.3. + *

The Login interface was introduced in TopLink 10.1.3. + * @param session the DatabaseSession being logged in + * @param login the DatabaseLogin injected by Spring + * @see oracle.toplink.sessions.DatabaseSession#setLogin + */ + protected void setDatabaseLogin(DatabaseSession session, DatabaseLogin login) { + Method setLoginMethod = null; + try { + // Search for the new 10.1.3 Login interface... + Class loginClass = DatabaseSession.class.getClassLoader().loadClass("oracle.toplink.sessions.Login"); + setLoginMethod = DatabaseSession.class.getMethod("setLogin", new Class[] {loginClass}); + if (logger.isDebugEnabled()) { + logger.debug("Using TopLink 10.1.3 setLogin(Login) API"); + } + } + catch (Exception ex) { + // TopLink 10.1.3 Login interface not found -> + // fall back to TopLink 9.0.4's setLogin(DatabaseLogin) + if (logger.isDebugEnabled()) { + logger.debug("Using TopLink 9.0.4 setLogin(DatabaseLogin) API"); + } + session.setLogin(login); + return; + } + + // Invoke the 10.1.3 version: Session.setLogin(Login) + ReflectionUtils.invokeMethod(setLoginMethod, session, new Object[] {login}); + } + + /** + * Load the specified DatabaseSession from the TopLink sessions.xml + * configuration file. + * @param configLocation the class path location of the sessions.xml file + * @param sessionName the name of the TopLink Session in the configuration file + * @param sessionClassLoader the class loader to use + * @return the DatabaseSession instance + * @throws TopLinkException in case of errors + */ + protected DatabaseSession loadDatabaseSession( + String configLocation, String sessionName, ClassLoader sessionClassLoader) + throws TopLinkException { + + SessionManager manager = getSessionManager(); + + // Try to find TopLink 10.1.3 XMLSessionConfigLoader. + Method getSessionMethod = null; + Object loader = null; + try { + Class loaderClass = SessionManager.class.getClassLoader().loadClass( + "oracle.toplink.tools.sessionconfiguration.XMLSessionConfigLoader"); + getSessionMethod = SessionManager.class.getMethod("getSession", + new Class[] {loaderClass, String.class, ClassLoader.class, boolean.class, boolean.class, boolean.class}); + if (logger.isDebugEnabled()) { + logger.debug("Using TopLink 10.1.3 XMLSessionConfigLoader"); + } + Constructor ctor = loaderClass.getConstructor(new Class[] {String.class}); + loader = ctor.newInstance(new Object[] {configLocation}); + } + catch (Exception ex) { + // TopLink 10.1.3 XMLSessionConfigLoader not found -> + // fall back to TopLink 9.0.4 XMLLoader. + if (logger.isDebugEnabled()) { + logger.debug("Using TopLink 9.0.4 XMLLoader"); + } + XMLLoader xmlLoader = new XMLLoader(configLocation); + return (DatabaseSession) manager.getSession(xmlLoader, sessionName, sessionClassLoader, false, false); + } + + // TopLink 10.1.3 XMLSessionConfigLoader found -> create loader instance + // through reflection and fetch specified Session from SessionManager. + // This invocation will check if the ClassLoader passed in is the same + // as the one used to a session currently loaded with the same "sessionName" + // If the ClassLoaders are different, then this LocalSessionFactory is being + // re-loaded after a hot-deploy and the existing DatabaseSession will be logged + // out and re-built from scratch. + return (DatabaseSession) ReflectionUtils.invokeMethod(getSessionMethod, manager, + new Object[] {loader, sessionName, sessionClassLoader, Boolean.FALSE, Boolean.FALSE, Boolean.TRUE}); + } + + /** + * Return the TopLink SessionManager to use for loading DatabaseSessions. + *

The default implementation creates a new plain SessionManager instance, + * leading to completely independent TopLink Session instances. Could be + * overridden to return a shared or pre-configured SessionManager. + * @return the TopLink SessionManager instance + */ + protected SessionManager getSessionManager() { + return new SessionManager(); + } + + /** + * Create a new SessionFactory for the given TopLink DatabaseSession. + *

The default implementation creates a ServerSessionFactory for a + * ServerSession and a SingleSessionFactory for a plain DatabaseSession. + * @param session the TopLink DatabaseSession to create a SessionFactory for + * @return the SessionFactory + * @throws TopLinkException in case of errors + * @see ServerSessionFactory + * @see SingleSessionFactory + * @see oracle.toplink.threetier.ServerSession + * @see oracle.toplink.sessions.DatabaseSession + */ + protected SessionFactory newSessionFactory(DatabaseSession session) { + if (session instanceof ServerSession) { + return new ServerSessionFactory((ServerSession) session); + } + else if (session instanceof SessionBroker) { + return new SessionBrokerSessionFactory((SessionBroker) session); + } + else { + return new SingleSessionFactory(session); + } + } + +} Index: 3rdParty_sources/spring/org/springframework/orm/toplink/LocalSessionFactoryBean.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/toplink/LocalSessionFactoryBean.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/orm/toplink/LocalSessionFactoryBean.java 17 Aug 2012 15:16:11 -0000 1.1 @@ -0,0 +1,160 @@ +/* + * 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.toplink; + +import java.sql.SQLException; + +import oracle.toplink.exceptions.DatabaseException; +import oracle.toplink.exceptions.TopLinkException; + +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.jdbc.support.SQLExceptionTranslator; + +/** + * {@link org.springframework.beans.factory.FactoryBean} that creates a + * TopLink {@link SessionFactory}. This is the usual way to set up a shared + * TopLink SessionFactory in a Spring application context; the SessionFactory + * can then be passed to TopLink-based DAOs via dependency injection. + * + *

See the base class {@link LocalSessionFactory} for configuration details. + * + *

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 LocalSessionFactoryBean automatically enables a + * PersistenceExceptionTranslationPostProcessor to translate TopLink exceptions. + * + *

If your DAOs expect to receive a raw TopLink Session, consider defining a + * {@link org.springframework.orm.toplink.support.TransactionAwareSessionAdapter} + * in front of this bean. This adapter will provide a TopLink Session rather + * than a SessionFactory as bean reference. Your DAOs can then, for example, + * access the currently active Session and UnitOfWork via + * Session.getActiveSession() and Session.getActiveUnitOfWork(), + * respectively. Note that you can still access the SessionFactory as well, by + * defining a bean reference that points directly at the LocalSessionFactoryBean. + * + * @author Juergen Hoeller + * @since 1.2 + * @see LocalSessionFactory + * @see org.springframework.orm.toplink.support.TransactionAwareSessionAdapter + * @see org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor + */ +public class LocalSessionFactoryBean extends LocalSessionFactory + implements FactoryBean, BeanClassLoaderAware, InitializingBean, DisposableBean, PersistenceExceptionTranslator { + + private SessionFactory sessionFactory; + + private SQLExceptionTranslator jdbcExceptionTranslator; + + + /** + * Set the JDBC exception translator for this SessionFactory. + *

Applied to any SQLException root cause of a TopLink DatabaseException, + * within Spring's PersistenceExceptionTranslator mechanism. + * The default is to rely on TopLink's native exception translation. + * @see oracle.toplink.exceptions.DatabaseException + * @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; + } + + /** + * Sets the given bean ClassLoader as TopLink Session ClassLoader. + * @see #setSessionClassLoader + */ + public void setBeanClassLoader(ClassLoader classLoader) { + setSessionClassLoader(classLoader); + } + + public void afterPropertiesSet() throws TopLinkException { + this.sessionFactory = createSessionFactory(); + } + + + 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 TopLinkException; + * else returns null to indicate an unknown exception. + * @see org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor + * @see #convertTopLinkAccessException + */ + public DataAccessException translateExceptionIfPossible(RuntimeException ex) { + if (ex instanceof TopLinkException) { + return convertTopLinkAccessException((TopLinkException) ex); + } + return null; + } + + /** + * Convert the given TopLinkException to an appropriate exception from the + * org.springframework.dao hierarchy. + *

Will automatically apply a specified SQLExceptionTranslator to a + * TopLink DatabaseException, else rely on TopLink's default translation. + * @param ex TopLinkException that occured + * @return a corresponding DataAccessException + * @see SessionFactoryUtils#convertTopLinkAccessException + * @see #setJdbcExceptionTranslator + */ + public DataAccessException convertTopLinkAccessException(TopLinkException ex) { + if (getJdbcExceptionTranslator() != null && ex instanceof DatabaseException) { + Throwable internalEx = ex.getInternalException(); + // Should always be a SQLException inside a DatabaseException. + if (internalEx instanceof SQLException) { + return getJdbcExceptionTranslator().translate( + "TopLink operation: " + ex.getMessage(), null, (SQLException) internalEx); + } + } + return SessionFactoryUtils.convertTopLinkAccessException(ex); + } + + + public void destroy() { + logger.info("Closing TopLink SessionFactory"); + this.sessionFactory.close(); + } + +} Index: 3rdParty_sources/spring/org/springframework/orm/toplink/ServerSessionFactory.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/toplink/ServerSessionFactory.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/orm/toplink/ServerSessionFactory.java 17 Aug 2012 15:16:11 -0000 1.1 @@ -0,0 +1,80 @@ +/* + * 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.toplink; + +import oracle.toplink.exceptions.TopLinkException; +import oracle.toplink.sessions.Session; +import oracle.toplink.threetier.ServerSession; + +/** + * Full-fledged default implementation of the SessionFactory interface: + * creates ClientSessions for a given ServerSession. + * + *

Can create a special ClientSession subclass for managed Sessions, carrying + * an active UnitOfWork that expects to be committed at transaction completion + * (just like a plain TopLink Session does within a JTA transaction). + * + *

Can also create a transaction-aware Session reference that returns the + * active transactional Session on getActiveSession. + * + * @author Juergen Hoeller + * @since 1.2 + * @see SingleSessionFactory + * @see oracle.toplink.sessions.Session#getActiveUnitOfWork() + * @see oracle.toplink.sessions.Session#getActiveSession() + */ +public class ServerSessionFactory extends AbstractSessionFactory { + + private final ServerSession serverSession; + + + /** + * Create a new ServerSessionFactory for the given ServerSession. + * @param serverSession the TopLink ServerSession to create ClientSessions for + */ + public ServerSessionFactory(ServerSession serverSession) { + this.serverSession = serverSession; + } + + + /** + * Return this factory's ServerSession as-is. + */ + protected Session getMasterSession() { + return this.serverSession; + } + + /** + * Create a plain ClientSession for this factory's ServerSession. + * @see oracle.toplink.threetier.ServerSession#acquireClientSession() + */ + protected Session createClientSession() throws TopLinkException { + return this.serverSession.acquireClientSession(); + } + + + /** + * Shut the pre-configured TopLink ServerSession down. + * @see oracle.toplink.sessions.DatabaseSession#logout() + * @see oracle.toplink.sessions.Session#release() + */ + public void close() { + this.serverSession.logout(); + this.serverSession.release(); + } + +} Index: 3rdParty_sources/spring/org/springframework/orm/toplink/SessionBrokerSessionFactory.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/toplink/SessionBrokerSessionFactory.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/orm/toplink/SessionBrokerSessionFactory.java 17 Aug 2012 15:16:11 -0000 1.1 @@ -0,0 +1,106 @@ +/* + * 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.toplink; + +import oracle.toplink.exceptions.TopLinkException; +import oracle.toplink.exceptions.ValidationException; +import oracle.toplink.sessionbroker.SessionBroker; +import oracle.toplink.sessions.Session; + +/** + * Spring SessionFactory implementation allowing users to + * inject a TopLink Session built from a TopLink SessionBroker. + * + * SessionBrokers are used identically to any other TopLink Session. DAO code + * should never have to distinguish between Sessions which broker requests to + * multiple databases and Sessions which manage requests to a single database. + * + * The only pertinent difference in the SessionBroker api involves the method + * for obtaining a thread-safe "client" Session from the SessionBroker. + * Instead of the typical acquireClientSession + * method, this SessionFactory implementation uses the + * acquireClientSessionBroker method. + * If a SessionBroker aggregates non thread-safe DatabaseSessions, + * the factory will throw UnsupportedOperationExceptions + * if used to create managed or transaction-aware Sessions. + * + * @author James Clark + * @author Juergen Hoeller + * @since 1.2.6 + * @see org.springframework.orm.toplink.ServerSessionFactory + * @see oracle.toplink.threetier.ServerSession#acquireClientSession() + * @see oracle.toplink.sessionbroker.SessionBroker#acquireClientSessionBroker() + */ +public class SessionBrokerSessionFactory extends AbstractSessionFactory { + + private final SessionBroker sessionBroker; + + + /** + * Create a new SessionBrokerSessionFactory for the given SessionBroker. + * @param broker the TopLink SessionBroker to fetch Sessions from + */ + public SessionBrokerSessionFactory(SessionBroker broker) { + this.sessionBroker = broker; + } + + + /** + * Try to create a client Session; fall back to the master Session, + * if no client Session can be created (because of the session broker's + * configuration). + * @see #createClientSession() + * @see #getMasterSession() + */ + public Session createSession() throws TopLinkException { + try { + return createClientSession(); + } + catch (ValidationException ex) { + logger.debug( + "Could not create TopLink client session for SessionBroker - returning SessionBroker itself", ex); + return getMasterSession(); + } + } + + /** + * Return this factory's SessionBroker as-is. + */ + protected Session getMasterSession() { + return this.sessionBroker; + } + + /** + * Create a plain client SessionBroker for this factory's ServerSession. + * @see oracle.toplink.sessionbroker.SessionBroker#acquireClientSessionBroker() + */ + protected Session createClientSession() throws TopLinkException { + return this.sessionBroker.acquireClientSessionBroker(); + } + + + /** + * Shut the pre-configured TopLink SessionBroker down. + * @see oracle.toplink.sessions.DatabaseSession#logout() + * @see oracle.toplink.sessions.Session#release() + */ + public void close() { + this.sessionBroker.logout(); + this.sessionBroker.release(); + } + +} Index: 3rdParty_sources/spring/org/springframework/orm/toplink/SessionFactory.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/toplink/SessionFactory.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/orm/toplink/SessionFactory.java 17 Aug 2012 15:16:11 -0000 1.1 @@ -0,0 +1,95 @@ +/* + * 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.toplink; + +import oracle.toplink.exceptions.TopLinkException; +import oracle.toplink.sessions.Session; + +/** + * The SessionFactory interface serves as factory for TopLink Sessions, + * allowing for dependency injection on thread-safe TopLink-based DAOs. + * Used by TopLinkAccessor/Template and TopLinkTransactionManager. + * + *

In contrast to JDO or Hibernate (which define native PersistenceManagerFactory + * and SessionFactory interfaces, respectively), TopLink itself does not provide + * such a factory interface: hence, it is necessary to define it within Spring. + * Note that this interface does not depend on any other Spring interfaces or + * classes, to allow for keeping TopLink-based DAOs as independent as possible. + * + * @author Juergen Hoeller + * @since 1.2 + * @see TopLinkAccessor#setSessionFactory + * @see TopLinkTransactionManager#setSessionFactory + */ +public interface SessionFactory { + + /** + * Create a plain TopLink Session for the current application context. + * Will usually be a new ClientSession for the current thread. + *

The returned Session will participate in JTA transactions (provided that + * TopLink is configured with a corresponding external transaction controller), + * but not in Spring-managed transactions (by TopLinkTransactionManager). + *

This is the factory method to be called by TopLink data access code, + * usually through the SessionFactoryUtils.getSession method + * that checks for a transactional (thread-bound) Session first. + * @return the new TopLink Session + * @throws TopLinkException in case of errors + * @see SessionFactoryUtils#getSession(SessionFactory, boolean) + */ + Session createSession() throws TopLinkException; + + /** + * Create a new managed TopLink client Session for the current context. + * Will usually be a new special ClientSession for the current thread. + *

The returned Session will be prepared to be managed within a Spring + * transaction (by TopLinkTransactionManager). It will carry an active + * UnitOfWork that expects to be committed at transaction completion, + * just like a plain TopLink Session does within a JTA transaction. + *

This method is only supposed to be called by Spring's + * TopLinkTransactionManager or similar TopLink-based transaction managers. + * If a SessionFactory does not support managed Sessions, it should throw + * an UnsupportedOperationException. + * @return the new TopLink Session + * @throws TopLinkException in case of errors + * @see oracle.toplink.sessions.Session#getActiveUnitOfWork() + */ + Session createManagedClientSession() throws TopLinkException; + + /** + * Create a new transaction-aware TopLink Session that exposes the currently + * active Session and UnitOfWork via Session.getActiveSession() + * and Session.getActiveUnitOfWork(), respectively. + *

Such a Session reference can be used analogously to a managed TopLink + * Session in a JTA environment, with Spring-managed transactions backing it. + *

It is usually preferable to let DAOs work with a full SessionFactory, + * accessing TopLink Sessions via SessionFactoryUtils.getSession. + * However, a transaction-aware TopLink Session reference does not impose any + * Spring dependency, so might be preferable if you'd like to keep your data + * access code tied to TopLink API only. + * @return the new TopLink Session + * @throws TopLinkException in case of errors + * @see oracle.toplink.sessions.Session#getActiveSession() + * @see oracle.toplink.sessions.Session#getActiveUnitOfWork() + */ + Session createTransactionAwareSession() throws TopLinkException; + + /** + * Close this SessionFactory, shutting down all internal resources. + */ + void close(); + +} Index: 3rdParty_sources/spring/org/springframework/orm/toplink/SessionFactoryUtils.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/toplink/SessionFactoryUtils.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/orm/toplink/SessionFactoryUtils.java 17 Aug 2012 15:16:11 -0000 1.1 @@ -0,0 +1,235 @@ +/* + * 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.toplink; + +import oracle.toplink.exceptions.ConcurrencyException; +import oracle.toplink.exceptions.ConversionException; +import oracle.toplink.exceptions.DatabaseException; +import oracle.toplink.exceptions.OptimisticLockException; +import oracle.toplink.exceptions.QueryException; +import oracle.toplink.exceptions.TopLinkException; +import oracle.toplink.sessions.Session; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import org.springframework.dao.ConcurrencyFailureException; +import org.springframework.dao.DataAccessException; +import org.springframework.dao.DataAccessResourceFailureException; +import org.springframework.dao.TypeMismatchDataAccessException; +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 TopLink Session handling, + * allowing for reuse of TopLink Session instances within transactions. + * Also provides support for exception translation. + * + *

Mainly intended for internal use within the framework. + * + * @author Juergen Hoeller + * @author James Clark + * @since 1.2 + */ +public abstract class SessionFactoryUtils { + + private static final Log logger = LogFactory.getLog(SessionFactoryUtils.class); + + + /** + * Get a TopLink Session for the given SessionFactory. Is aware of and will + * return any existing corresponding Session bound to the current thread, for + * example when using TopLinkTransactionManager. 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 TopLinkTemplate allows to write data access code + * without caring about such resource handling. + * @param sessionFactory TopLink SessionFactory to create the session with + * @param allowCreate if a non-transactional Session should be created when no + * transactional Session can be found for the current thread + * @return the TopLink Session + * @throws DataAccessResourceFailureException if the Session couldn't be created + * @throws IllegalStateException if no thread-bound Session found and + * "allowCreate" is false + * @see #releaseSession + * @see TopLinkTemplate + */ + public static Session getSession(SessionFactory sessionFactory, boolean allowCreate) + throws DataAccessResourceFailureException, IllegalStateException { + + try { + return doGetSession(sessionFactory, allowCreate); + } + catch (TopLinkException ex) { + throw new DataAccessResourceFailureException("Could not open TopLink Session", ex); + } + } + + /** + * Get a TopLink Session for the given SessionFactory. Is aware of and will + * return any existing corresponding Session bound to the current thread, for + * example when using TopLinkTransactionManager. Will create a new Session + * otherwise, if "allowCreate" is true. + *

Same as getSession, but throwing the original TopLinkException. + * @param sessionFactory TopLink SessionFactory to create the session with + * @param allowCreate if a non-transactional Session should be created when no + * transactional Session can be found for the current thread + * @return the TopLink Session + * @throws TopLinkException if the Session couldn't be created + * @throws IllegalStateException if no thread-bound Session found and + * "allowCreate" is false + * @see #releaseSession + * @see TopLinkTemplate + */ + public static Session doGetSession(SessionFactory sessionFactory, boolean allowCreate) + throws TopLinkException, IllegalStateException { + + Assert.notNull(sessionFactory, "No SessionFactory specified"); + + SessionHolder sessionHolder = + (SessionHolder) TransactionSynchronizationManager.getResource(sessionFactory); + if (sessionHolder != null) { + return sessionHolder.getSession(); + } + + if (!allowCreate && !TransactionSynchronizationManager.isSynchronizationActive()) { + throw new IllegalStateException("No TopLink Session bound to thread, " + + "and configuration does not allow creation of non-transactional one here"); + } + + logger.debug("Creating TopLink Session"); + Session session = sessionFactory.createSession(); + + if (TransactionSynchronizationManager.isSynchronizationActive()) { + logger.debug("Registering new Spring transaction synchronization for new TopLink Session"); + // Use same Session for further TopLink actions within the transaction. + // Thread object will get removed by synchronization at transaction completion. + sessionHolder = new SessionHolder(session); + sessionHolder.setSynchronizedWithTransaction(true); + TransactionSynchronizationManager.registerSynchronization( + new SessionSynchronization(sessionHolder, sessionFactory)); + TransactionSynchronizationManager.bindResource(sessionFactory, sessionHolder); + } + + return session; + } + + /** + * Return whether the given TopLink Session is transactional, that is, + * bound to the current thread by Spring's transaction facilities. + * @param session the TopLink Session to check + * @param sessionFactory TopLink SessionFactory that the Session was created with + * (can 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 && session == sessionHolder.getSession()); + } + + /** + * Convert the given TopLinkException to an appropriate exception from the + * org.springframework.dao hierarchy. + * @param ex TopLinkException that occured + * @return the corresponding DataAccessException instance + */ + public static DataAccessException convertTopLinkAccessException(TopLinkException ex) { + if (ex instanceof DatabaseException) { + // SQLException during TopLink access: only passed in here from custom code, + // as TopLinkTemplate will use SQLExceptionTranslator-based handling. + return new TopLinkJdbcException((DatabaseException) ex); + } + if (ex instanceof OptimisticLockException) { + return new TopLinkOptimisticLockingFailureException((OptimisticLockException) ex); + } + if (ex instanceof QueryException) { + return new TopLinkQueryException((QueryException) ex); + } + if (ex instanceof ConcurrencyException) { + return new ConcurrencyFailureException(ex.getMessage(), ex); + } + if (ex instanceof ConversionException) { + return new TypeMismatchDataAccessException(ex.getMessage(), ex); + } + // fallback + return new TopLinkSystemException(ex); + } + + /** + * 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 TopLink Session to close + * @param sessionFactory TopLink SessionFactory that the Session was created with + * (can be null) + */ + public static void releaseSession(Session session, SessionFactory sessionFactory) { + if (session == null) { + return; + } + // Only release non-transactional Sessions. + if (!isSessionTransactional(session, sessionFactory)) { + doRelease(session); + } + } + + /** + * Perform the actual releasing of the TopLink Session. + * @param session the TopLink Session to release + */ + private static void doRelease(Session session) { + if (session != null) { + logger.debug("Closing TopLink Session"); + try { + session.release(); + } + catch (TopLinkException ex) { + logger.debug("Could not close TopLink Session", ex); + } + catch (Throwable ex) { + logger.debug("Unexpected exception on closing TopLink Session", ex); + } + } + } + + + /** + * Callback for resource cleanup at the end of a Spring-managed JTA transaction, + * i.e. when participating in a JtaTransactionManager transaction. + * @see org.springframework.transaction.jta.JtaTransactionManager + */ + private static class SessionSynchronization extends ResourceHolderSynchronization { + + public SessionSynchronization(SessionHolder sessionHolder, SessionFactory sessionFactory) { + super(sessionHolder, sessionFactory); + } + + protected boolean shouldReleaseBeforeCompletion() { + return false; + } + + protected void releaseResource(ResourceHolder resourceHolder, Object resourceKey) { + releaseSession(((SessionHolder) resourceHolder).getSession(), (SessionFactory) resourceKey); + } + } + +} Index: 3rdParty_sources/spring/org/springframework/orm/toplink/SessionHolder.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/toplink/SessionHolder.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/orm/toplink/SessionHolder.java 17 Aug 2012 15:16:11 -0000 1.1 @@ -0,0 +1,55 @@ +/* + * 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.toplink; + +import oracle.toplink.sessions.Session; + +import org.springframework.transaction.support.ResourceHolderSupport; +import org.springframework.util.Assert; + +/** + * Session holder, wrapping a TopLink Session. + * TopLinkTransactionManager 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 + */ +public class SessionHolder extends ResourceHolderSupport { + + private final Session session; + + + /** + * Create a new SessionHolder for the given TopLink Session. + * @param session the TopLink Session + */ + public SessionHolder(Session session) { + Assert.notNull(session, "Session must not be null"); + this.session = session; + } + + /** + * Return this holder's TopLink Session. + */ + public Session getSession() { + return session; + } + +} Index: 3rdParty_sources/spring/org/springframework/orm/toplink/SessionReadCallback.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/toplink/SessionReadCallback.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/orm/toplink/SessionReadCallback.java 17 Aug 2012 15:16:11 -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.toplink; + +import oracle.toplink.exceptions.TopLinkException; +import oracle.toplink.sessions.Session; +import oracle.toplink.sessions.UnitOfWork; + +/** + * Convenient abstract implementation of the TopLinkCallback interface, + * exposing either the plain TopLink Session or the TopLink UnitOfWork + * (which extends the Session interface) to code that reads persistent objects. + * + *

Exposes the UnitOfWork if there is an active one (that is, if we're running + * within a non-read-only transaction); else exposes the Session itself. + * This allows to modify returned objects within a transaction, which is + * often desired, while the same code will return shared cache objects + * if running outside a transaction. + * + *

If "enforceReadOnly" is demanded, the callback will always expose the + * Session itself, avoiding the UnitOfWork overhead in any case. + * + * @author Juergen Hoeller + * @since 1.2 + * @see oracle.toplink.sessions.Session#getActiveUnitOfWork() + * @see #readFromSession(oracle.toplink.sessions.Session) + */ +public abstract class SessionReadCallback implements TopLinkCallback { + + private final boolean enforceReadOnly; + + /** + * Create a new SessionReadCallback, not enforcing read-only objects. + */ + public SessionReadCallback() { + this.enforceReadOnly = false; + } + + /** + * Create a new SessionReadCallback, enforcing read-only objects if demanded. + * @param enforceReadOnly whether to enforce returning read-only objects, + * even if running within a non-read-only transaction + */ + public SessionReadCallback(boolean enforceReadOnly) { + this.enforceReadOnly = enforceReadOnly; + } + + /** + * Determines the Session to work on (either the active UnitOfWork + * or the plain Session) and delegates to readFromSession. + * @see #readFromSession(oracle.toplink.sessions.Session) + */ + public final Object doInTopLink(Session session) throws TopLinkException { + Session sessionToUse = session; + if (!this.enforceReadOnly) { + UnitOfWork unitOfWork = session.getActiveUnitOfWork(); + if (unitOfWork != null) { + sessionToUse = unitOfWork; + } + } + return readFromSession(sessionToUse); + } + + /** + * Called with a Session to work on, either the active UnitOfWork + * or the plain Session (as determined by the transaction status). + * @param session the TopLink Session to perform read operations on + * @return a result object, or null if none + * @throws TopLinkException in case of TopLink errors + */ + protected abstract Object readFromSession(Session session) throws TopLinkException; + +} Index: 3rdParty_sources/spring/org/springframework/orm/toplink/SingleSessionFactory.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/toplink/SingleSessionFactory.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/orm/toplink/SingleSessionFactory.java 17 Aug 2012 15:16:11 -0000 1.1 @@ -0,0 +1,83 @@ +/* + * 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.toplink; + +import oracle.toplink.sessions.DatabaseSession; +import oracle.toplink.sessions.Session; + +/** + * Simple implementation of the SessionFactory interface: always returns + * the passed-in Session as-is. + * + *

Useful for testing or standalone usage of TopLink-based data access objects. + * In a server environment, use ServerSessionFactory instead. + * + * @author Juergen Hoeller + * @since 1.2 + * @see ServerSessionFactory + */ +public class SingleSessionFactory implements SessionFactory { + + private final Session session; + + + /** + * Create a new SingleSessionFactory with the given Session. + * @param session the TopLink Session to hold + */ + public SingleSessionFactory(Session session) { + this.session = session; + } + + + /** + * Return the held TopLink Session as-is. + */ + public Session createSession() { + return this.session; + } + + /** + * Throws an UnsupportedOperationException: SingleSessionFactory does not + * support managed client Sessions. Use ServerSessionFactory instead. + */ + public Session createManagedClientSession() { + throw new UnsupportedOperationException("SingleSessionFactory does not support managed client Sessions"); + } + + /** + * Throws an UnsupportedOperationException: SingleSessionFactory does not + * support transaction-aware Sessions. Use ServerSessionFactory instead. + */ + public Session createTransactionAwareSession() { + throw new UnsupportedOperationException("SingleSessionFactory does not support transaction-aware Sessions"); + } + + + /** + * Shut the pre-configured TopLink Session down. + * @see oracle.toplink.sessions.DatabaseSession#logout() + * @see oracle.toplink.sessions.Session#release() + */ + public void close() { + if (this.session instanceof DatabaseSession) { + ((DatabaseSession) this.session).logout(); + } + this.session.release(); + } + +} Index: 3rdParty_sources/spring/org/springframework/orm/toplink/TopLinkAccessor.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/toplink/TopLinkAccessor.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/orm/toplink/TopLinkAccessor.java 17 Aug 2012 15:16:11 -0000 1.1 @@ -0,0 +1,131 @@ +/* + * 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.toplink; + +import java.sql.SQLException; + +import oracle.toplink.exceptions.DatabaseException; +import oracle.toplink.exceptions.TopLinkException; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import org.springframework.beans.factory.InitializingBean; +import org.springframework.dao.DataAccessException; +import org.springframework.jdbc.support.SQLExceptionTranslator; + +/** + * Base class for TopLinkTemplate and TopLinkInterceptor, defining common properties + * such as SessionFactory and JDBC exception translator. + * + *

Not intended to be used directly. See TopLinkTemplate and TopLinkInterceptor. + * + *

Thanks to Slavik Markovich for implementing the initial TopLink support prototype! + * + * @author Juergen Hoeller + * @since 1.2 + * @see TopLinkTemplate + * @see TopLinkInterceptor + */ +public abstract class TopLinkAccessor implements InitializingBean { + + /** Logger available to subclasses */ + protected final Log logger = LogFactory.getLog(getClass()); + + private SessionFactory sessionFactory; + + private SQLExceptionTranslator jdbcExceptionTranslator; + + + /** + * Set the the TopLink SessionFactory that should be used to create TopLink + * Sessions. This will usually be a ServerSessionFactory in a multi-threaded + * environment, but can also be a SingleSessionFactory for testing purposes + * or for standalone execution. + *

The passed-in SessionFactory will usually be asked for a plain Session + * to perform data access on, unless an active transaction with a thread-bound + * Session is found. + * @see ServerSessionFactory + * @see SingleSessionFactory + * @see SessionFactory#createSession() + * @see SessionFactoryUtils#getSession(SessionFactory, boolean) + */ + public void setSessionFactory(SessionFactory sessionFactory) { + this.sessionFactory = sessionFactory; + } + + /** + * Return the TopLink SessionFactory that should be used to create + * TopLink Sessions. + */ + public SessionFactory getSessionFactory() { + return sessionFactory; + } + + /** + * Set the JDBC exception translator for this instance. + *

Applied to any SQLException root cause of a TopLink DatabaseException. + * The default is to rely on TopLink's native exception translation. + * @param jdbcExceptionTranslator the exception translator + * @see oracle.toplink.exceptions.DatabaseException + * @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; + } + + + /** + * Check that we were provided with a session to use + */ + public void afterPropertiesSet() { + if (this.sessionFactory == null) { + throw new IllegalArgumentException("sessionFactory is required"); + } + } + + + /** + * Convert the given TopLinkException to an appropriate exception from the + * org.springframework.dao hierarchy. + *

Will automatically apply a specified SQLExceptionTranslator to a + * TopLink DatabaseException, else rely on TopLink's default translation. + * @param ex TopLinkException that occured + * @return a corresponding DataAccessException + * @see SessionFactoryUtils#convertTopLinkAccessException + * @see #setJdbcExceptionTranslator + */ + public DataAccessException convertTopLinkAccessException(TopLinkException ex) { + if (getJdbcExceptionTranslator() != null && ex instanceof DatabaseException) { + Throwable internalEx = ex.getInternalException(); + // Should always be a SQLException inside a DatabaseException. + if (internalEx instanceof SQLException) { + return getJdbcExceptionTranslator().translate( + "TopLink operation: " + ex.getMessage(), null, (SQLException) internalEx); + } + } + return SessionFactoryUtils.convertTopLinkAccessException(ex); + } + +} Index: 3rdParty_sources/spring/org/springframework/orm/toplink/TopLinkCallback.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/toplink/TopLinkCallback.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/orm/toplink/TopLinkCallback.java 17 Aug 2012 15:16:11 -0000 1.1 @@ -0,0 +1,77 @@ +/* + * 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.toplink; + +import oracle.toplink.exceptions.TopLinkException; +import oracle.toplink.sessions.Session; + +/** + * Callback interface for TopLink code. To be used with {@link TopLinkTemplate}'s + * execution methods, often as anonymous classes within a method implementation. + * A typical implementation will call TopLink Session CRUD to perform some + * operations on persistent objects. + * + *

The Session that gets passed into the doInTopLink method + * is usually a thread-safe ClientSession. Since this provides access to the + * TopLink shared cache, it is possible for implementations of this interface to return + * references to read-only objects from the shared cache. These objects + * must not be modified by application code outside of the DAO layer. + * If persistent objects need to be edited, they should be loaded from (or registered with) + * a TopLink UnitOfWork, or they should be explicitly copied and merged back into a + * UnitOfWork at a later point of time. + * + *

Users can access a UnitOfWork by using the getActiveUnitOfWork + * method on the Session. Normally, this will only be done when there is an + * active non-read-only transaction being managed by Spring's {@link TopLinkTransactionManager} + * or by an external transaction controller (usually a J2EE server's JTA provider, + * configured in TopLink). The getActiveUnitOfWork method will return + * null outside of a managed transaction. + * + * @author Juergen Hoeller + * @author James Clark + * @see TopLinkTemplate + * @see TopLinkTransactionManager + */ +public interface TopLinkCallback { + + /** + * Gets called by TopLinkTemplate.execute with an active + * Session. Does not need to care about activating or closing + * the TopLink Session, or handling transactions. + * + *

Note that write operations should usually be performed on the active + * UnitOfWork within an externally controlled transaction, through + * calling getActiveUnitOfWork. However, an implementation can also + * choose to use acquireUnitOfWork to create an independent + * UnitOfWork, which it needs to commit at the end of the operation. + * + *

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 TopLink Session + * @return a result object, or null if none + * @throws TopLinkException if thrown by the TopLink API + * @see oracle.toplink.sessions.Session#getActiveUnitOfWork() + * @see oracle.toplink.sessions.Session#acquireUnitOfWork() + * @see TopLinkTemplate#execute + * @see TopLinkTemplate#executeFind + */ + Object doInTopLink(Session session) throws TopLinkException; + +} Index: 3rdParty_sources/spring/org/springframework/orm/toplink/TopLinkInterceptor.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/toplink/TopLinkInterceptor.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/orm/toplink/TopLinkInterceptor.java 17 Aug 2012 15:16:11 -0000 1.1 @@ -0,0 +1,117 @@ +/* + * 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.toplink; + +import oracle.toplink.exceptions.TopLinkException; +import oracle.toplink.sessions.Session; +import org.aopalliance.intercept.MethodInterceptor; +import org.aopalliance.intercept.MethodInvocation; + +import org.springframework.transaction.support.TransactionSynchronizationManager; + +/** + * This interceptor binds a new TopLink 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 TopLinkTransactionManager, + * or from a surrounding TopLink-intercepted method), the interceptor simply + * takes part in it. + * + *

Application code must retrieve a TopLink Session via the + * SessionFactoryUtils.getSession method or - preferably - + * TopLink's own Session.getActiveSession() method, to be able to + * detect a thread-bound Session. Typically, the code will look like as follows: + * + *

+ * public void doSomeDataAccessAction() {
+ *   Session session = this.serverSession.getActiveSession();
+ *   ...
+ * }
+ * + * Note that this interceptor automatically translates TopLinkExceptions, + * via delegating to the SessionFactoryUtils.convertTopLikAccessException + * method that converts them to exceptions that are compatible with the + * org.springframework.dao exception hierarchy (like TopLinkTemplate does). + * This can be turned off if the raw exceptions are preferred. + * + *

This class can be considered a declarative alternative to TopLinkTemplate'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 potentially executing outside of transactions + * and/or when relying on exception translation. + * + * @author Juergen Hoeller + * @since 1.2 + */ +public class TopLinkInterceptor extends TopLinkAccessor implements MethodInterceptor { + + private boolean exceptionConversionEnabled = true; + + + /** + * Set whether to convert any TopLinkException 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; + Session session = SessionFactoryUtils.getSession(getSessionFactory(), true); + if (TransactionSynchronizationManager.hasResource(getSessionFactory())) { + logger.debug("Found thread-bound Session for TopLink interceptor"); + existingTransaction = true; + } + else { + logger.debug("Using new Session for TopLink interceptor"); + TransactionSynchronizationManager.bindResource(getSessionFactory(), new SessionHolder(session)); + } + try { + return methodInvocation.proceed(); + } + catch (TopLinkException ex) { + if (this.exceptionConversionEnabled) { + throw convertTopLinkAccessException(ex); + } + else { + throw ex; + } + } + finally { + if (existingTransaction) { + logger.debug("Not closing pre-bound TopLink Session after interceptor"); + } + else { + TransactionSynchronizationManager.unbindResource(getSessionFactory()); + SessionFactoryUtils.releaseSession(session, getSessionFactory()); + } + } + } + +} Index: 3rdParty_sources/spring/org/springframework/orm/toplink/TopLinkJdbcException.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/toplink/TopLinkJdbcException.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/orm/toplink/TopLinkJdbcException.java 17 Aug 2012 15:16:11 -0000 1.1 @@ -0,0 +1,37 @@ +/* + * 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.toplink; + +import oracle.toplink.exceptions.DatabaseException; + +import org.springframework.dao.UncategorizedDataAccessException; + +/** + * TopLink-specific subclass of DataAccessException, for JDBC exceptions + * that TopLink rethrew. + * + * @author Juergen Hoeller + * @see SessionFactoryUtils#convertTopLinkAccessException + * @since 1.2 + */ +public class TopLinkJdbcException extends UncategorizedDataAccessException { + + public TopLinkJdbcException(DatabaseException ex) { + super("JDBC exception on TopLink data access: " + ex.getMessage(), ex.getInternalException()); + } + +} Index: 3rdParty_sources/spring/org/springframework/orm/toplink/TopLinkOperations.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/toplink/TopLinkOperations.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/orm/toplink/TopLinkOperations.java 17 Aug 2012 15:16:11 -0000 1.1 @@ -0,0 +1,703 @@ +/* + * 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.toplink; + +import java.util.Collection; +import java.util.List; + +import oracle.toplink.expressions.Expression; +import oracle.toplink.queryframework.Call; +import oracle.toplink.queryframework.DatabaseQuery; +import oracle.toplink.sessions.ObjectCopyingPolicy; + +import org.springframework.dao.DataAccessException; + +/** + * Interface that specifies a basic set of TopLink operations, + * implemented by {@link TopLinkTemplate}. Not often used, but a useful + * option to enhance testability, as it can easily be mocked or stubbed. + * + *

Defines TopLinkTemplate's data access methods that + * mirror various TopLink {@link oracle.toplink.sessions.Session} / + * {@link oracle.toplink.sessions.UnitOfWork} methods. Users are + * strongly encouraged to read the TopLink javadocs for details + * on the semantics of those methods. + * + * @author Juergen Hoeller + * @since 1.2 + */ +public interface TopLinkOperations { + + /** + * Execute the action specified by the given action object within a + * TopLink Session. Application exceptions thrown by the action object + * get propagated to the caller (can only be unchecked). TopLink 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 TopLinkTransactionManager. + * @param action callback object that specifies the TopLink action + * @return a result object returned by the action, or null + * @throws org.springframework.dao.DataAccessException in case of TopLink errors + * @see TopLinkTransactionManager + * @see org.springframework.dao + * @see org.springframework.transaction + * @see oracle.toplink.sessions.Session + */ + Object execute(TopLinkCallback action) throws DataAccessException; + + /** + * Execute the specified action assuming that the result object is a + * Collection. This is a convenience method for executing TopLink queries + * within an action. + * @param action callback object that specifies the TopLink action + * @return a Collection result returned by the action, or null + * @throws org.springframework.dao.DataAccessException in case of TopLink errors + */ + List executeFind(TopLinkCallback action) throws DataAccessException; + + + //------------------------------------------------------------------------- + // Convenience methods for executing generic queries + //------------------------------------------------------------------------- + + /** + * Execute a given named query with the given arguments. + *

Retrieves read-write objects from the TopLink UnitOfWork in case of a + * non-read-only transaction, and read-only objects else. + * @param entityClass the entity class that has the named query descriptor + * @param queryName the name of the query + * @return the result object or list of result objects for the query + * (can be cast to the entity class or Collection/List, respectively) + * @throws org.springframework.dao.DataAccessException in case of TopLink errors + * @see oracle.toplink.sessions.Session#executeQuery(String, Class) + */ + Object executeNamedQuery(Class entityClass, String queryName) throws DataAccessException; + + /** + * Execute a given named query with the given arguments. + * @param entityClass the entity class that has the named query descriptor + * @param queryName the name of the query + * @param enforceReadOnly whether to always retrieve read-only objects from + * the plain TopLink Session (else, read-write objects will be retrieved + * from the TopLink UnitOfWork in case of a non-read-only transaction) + * @return the result object or list of result objects for the query + * (can be cast to the entity class or Collection/List, respectively) + * @throws org.springframework.dao.DataAccessException in case of TopLink errors + * @see oracle.toplink.sessions.Session#executeQuery(String, Class) + */ + Object executeNamedQuery(Class entityClass, String queryName, boolean enforceReadOnly) + throws DataAccessException; + + /** + * Execute a given named query with the given arguments. + *

Retrieves read-write objects from the TopLink UnitOfWork in case of a + * non-read-only transaction, and read-only objects else. + * @param entityClass the entity class that has the named query descriptor + * @param queryName the name of the query + * @param args the arguments for the query (can be null) + * @return the result object or list of result objects for the query + * (can be cast to the entity class or Collection/List, respectively) + * @throws org.springframework.dao.DataAccessException in case of TopLink errors + * @see oracle.toplink.sessions.Session#executeQuery(String, Class, java.util.Vector) + */ + Object executeNamedQuery(Class entityClass, String queryName, Object[] args) throws DataAccessException; + + /** + * Execute a given named query with the given arguments. + * @param entityClass the entity class that has the named query descriptor + * @param queryName the name of the query + * @param args the arguments for the query (can be null) + * @param enforceReadOnly whether to always retrieve read-only objects from + * the plain TopLink Session (else, read-write objects will be retrieved + * from the TopLink UnitOfWork in case of a non-read-only transaction) + * @return the result object or list of result objects for the query + * (can be cast to the entity class or Collection/List, respectively) + * @throws org.springframework.dao.DataAccessException in case of TopLink errors + * @see oracle.toplink.sessions.Session#executeQuery(String, Class, java.util.Vector) + */ + Object executeNamedQuery(Class entityClass, String queryName, Object[] args, boolean enforceReadOnly) + throws DataAccessException; + + /** + * Execute the given query object with the given arguments. + *

Retrieves read-write objects from the TopLink UnitOfWork in case of a + * non-read-only transaction, and read-only objects else. + * @param query the query object to execute (for example, + * a ReadObjectQuery or ReadAllQuery instance) + * @return the result object or list of result objects for the query + * (can be cast to the entity class or Collection/List, respectively) + * @throws org.springframework.dao.DataAccessException in case of TopLink errors + * @see oracle.toplink.sessions.Session#executeQuery(oracle.toplink.queryframework.DatabaseQuery) + */ + Object executeQuery(DatabaseQuery query) throws DataAccessException; + + /** + * Execute the given query object with the given arguments. + * @param query the query object to execute (for example, + * a ReadObjectQuery or ReadAllQuery instance) + * @param enforceReadOnly whether to always retrieve read-only objects from + * the plain TopLink Session (else, read-write objects will be retrieved + * from the TopLink UnitOfWork in case of a non-read-only transaction) + * @return the result object or list of result objects for the query + * (can be cast to the entity class or Collection/List, respectively) + * @throws org.springframework.dao.DataAccessException in case of TopLink errors + * @see oracle.toplink.sessions.Session#executeQuery(oracle.toplink.queryframework.DatabaseQuery) + */ + Object executeQuery(DatabaseQuery query, boolean enforceReadOnly) throws DataAccessException; + + /** + * Execute the given query object with the given arguments. + *

Retrieves read-write objects from the TopLink UnitOfWork in case of a + * non-read-only transaction, and read-only objects else. + * @param query the query object to execute (for example, + * a ReadObjectQuery or ReadAllQuery instance) + * @param args the arguments for the query (can be null) + * @return the result object or list of result objects for the query + * (can be cast to the entity class or Collection/List, respectively) + * @throws org.springframework.dao.DataAccessException in case of TopLink errors + * @see oracle.toplink.sessions.Session#executeQuery(oracle.toplink.queryframework.DatabaseQuery, java.util.Vector) + */ + Object executeQuery(DatabaseQuery query, Object[] args) throws DataAccessException; + + /** + * Execute the given query object with the given arguments. + * @param query the query object to execute (for example, + * a ReadObjectQuery or ReadAllQuery instance) + * @param args the arguments for the query (can be null) + * @param enforceReadOnly whether to always retrieve read-only objects from + * the plain TopLink Session (else, read-write objects will be retrieved + * from the TopLink UnitOfWork in case of a non-read-only transaction) + * @return the result object or list of result objects for the query + * (can be cast to the entity class or Collection/List, respectively) + * @throws org.springframework.dao.DataAccessException in case of TopLink errors + * @see oracle.toplink.sessions.Session#executeQuery(oracle.toplink.queryframework.DatabaseQuery, java.util.Vector) + */ + Object executeQuery(DatabaseQuery query, Object[] args, boolean enforceReadOnly) + throws DataAccessException; + + + //------------------------------------------------------------------------- + // Convenience methods for reading a specific set of objects + //------------------------------------------------------------------------- + + /** + * Read all entity instances of the given class. + *

Retrieves read-write objects from the TopLink UnitOfWork in case of a + * non-read-only transaction, and read-only objects else. + * @param entityClass the entity class + * @return the list of entity instances + * @throws org.springframework.dao.DataAccessException in case of TopLink errors + * @see oracle.toplink.sessions.Session#readAllObjects(Class) + */ + List readAll(Class entityClass) throws DataAccessException; + + /** + * Read all entity instances of the given class. + * @param entityClass the entity class + * @param enforceReadOnly whether to always retrieve read-only objects from + * the plain TopLink Session (else, read-write objects will be retrieved + * from the TopLink UnitOfWork in case of a non-read-only transaction) + * @return the list of entity instances + * @throws org.springframework.dao.DataAccessException in case of TopLink errors + * @see oracle.toplink.sessions.Session#readAllObjects(Class) + */ + List readAll(Class entityClass, boolean enforceReadOnly) throws DataAccessException; + + /** + * Read all entity instances of the given class that match the given expression. + *

Retrieves read-write objects from the TopLink UnitOfWork in case of a + * non-read-only transaction, and read-only objects else. + * @param entityClass the entity class + * @param expression the TopLink expression to match, + * usually built through the TopLink ExpressionBuilder + * @return the list of matching entity instances + * @throws org.springframework.dao.DataAccessException in case of TopLink errors + * @see oracle.toplink.sessions.Session#readAllObjects(Class, oracle.toplink.expressions.Expression) + * @see oracle.toplink.expressions.ExpressionBuilder + */ + List readAll(Class entityClass, Expression expression) throws DataAccessException; + + /** + * Read all entity instances of the given class that match the given expression. + * @param entityClass the entity class + * @param expression the TopLink expression to match, + * usually built through the TopLink ExpressionBuilder + * @param enforceReadOnly whether to always retrieve read-only objects from + * the plain TopLink Session (else, read-write objects will be retrieved + * from the TopLink UnitOfWork in case of a non-read-only transaction) + * @return the list of matching entity instances + * @throws org.springframework.dao.DataAccessException in case of TopLink errors + * @see oracle.toplink.sessions.Session#readAllObjects(Class, oracle.toplink.expressions.Expression) + * @see oracle.toplink.expressions.ExpressionBuilder + */ + List readAll(Class entityClass, Expression expression, boolean enforceReadOnly) + throws DataAccessException; + + /** + * Read all entity instances of the given class, as returned by the given call. + *

Retrieves read-write objects from the TopLink UnitOfWork in case of a + * non-read-only transaction, and read-only objects else. + * @param entityClass the entity class + * @param call the TopLink Call object to apply (either a SQLCall or an EJBQLCall) + * @return the list of matching entity instances + * @throws org.springframework.dao.DataAccessException in case of TopLink errors + * @see oracle.toplink.sessions.Session#readAllObjects(Class, oracle.toplink.queryframework.Call) + * @see oracle.toplink.queryframework.SQLCall + * @see oracle.toplink.queryframework.EJBQLCall + */ + List readAll(Class entityClass, Call call) throws DataAccessException; + + /** + * Read all entity instances of the given class, as returned by the given call. + * @param entityClass the entity class + * @param call the TopLink Call object to apply (either a SQLCall or an EJBQLCall) + * @param enforceReadOnly whether to always retrieve read-only objects from + * the plain TopLink Session (else, read-write objects will be retrieved + * from the TopLink UnitOfWork in case of a non-read-only transaction) + * @return the list of matching entity instances + * @throws org.springframework.dao.DataAccessException in case of TopLink errors + * @see oracle.toplink.sessions.Session#readAllObjects(Class, oracle.toplink.expressions.Expression) + * @see oracle.toplink.queryframework.SQLCall + * @see oracle.toplink.queryframework.EJBQLCall + */ + List readAll(Class entityClass, Call call, boolean enforceReadOnly) throws DataAccessException; + + /** + * Read an entity instance of the given class that matches the given expression. + *

Retrieves read-write objects from the TopLink UnitOfWork in case of a + * non-read-only transaction, and read-only objects else. + * @param entityClass the entity class + * @param expression the TopLink expression to match, + * usually built through the TopLink ExpressionBuilder + * @return the matching entity instance, or null if none found + * @throws org.springframework.dao.DataAccessException in case of TopLink errors + * @see oracle.toplink.sessions.Session#readAllObjects(Class, oracle.toplink.expressions.Expression) + * @see oracle.toplink.expressions.ExpressionBuilder + */ + Object read(Class entityClass, Expression expression) throws DataAccessException; + + /** + * Read an entity instance of the given class that matches the given expression. + * @param entityClass the entity class + * @param expression the TopLink expression to match, + * usually built through the TopLink ExpressionBuilder + * @param enforceReadOnly whether to always retrieve read-only objects from + * the plain TopLink Session (else, read-write objects will be retrieved + * from the TopLink UnitOfWork in case of a non-read-only transaction) + * @return a matching entity instance, or null if none found + * @throws org.springframework.dao.DataAccessException in case of TopLink errors + * @see oracle.toplink.sessions.Session#readAllObjects(Class, oracle.toplink.expressions.Expression) + * @see oracle.toplink.expressions.ExpressionBuilder + */ + Object read(Class entityClass, Expression expression, boolean enforceReadOnly) + throws DataAccessException; + + /** + * Read an entity instance of the given class, as returned by the given call. + *

Retrieves read-write objects from the TopLink UnitOfWork in case of a + * non-read-only transaction, and read-only objects else. + * @param entityClass the entity class + * @param call the TopLink Call object to apply (either a SQLCall or an EJBQLCall) + * @return a matching entity instance, or null if none found + * @throws org.springframework.dao.DataAccessException in case of TopLink errors + * @see oracle.toplink.sessions.Session#readAllObjects(Class, oracle.toplink.queryframework.Call) + * @see oracle.toplink.queryframework.SQLCall + * @see oracle.toplink.queryframework.EJBQLCall + */ + Object read(Class entityClass, Call call) throws DataAccessException; + + /** + * Read an entity instance of the given class, as returned by the given call. + * @param entityClass the entity class + * @param call the TopLink Call object to apply (either a SQLCall or an EJBQLCall) + * @param enforceReadOnly whether to always retrieve read-only objects from + * the plain TopLink Session (else, read-write objects will be retrieved + * from the TopLink UnitOfWork in case of a non-read-only transaction) + * @return a matching entity instance, or null if none found + * @throws org.springframework.dao.DataAccessException in case of TopLink errors + * @see oracle.toplink.sessions.Session#readAllObjects(Class, oracle.toplink.expressions.Expression) + * @see oracle.toplink.queryframework.SQLCall + * @see oracle.toplink.queryframework.EJBQLCall + */ + Object read(Class entityClass, Call call, boolean enforceReadOnly) + throws DataAccessException; + + + //------------------------------------------------------------------------- + // Convenience methods for reading an individual object by id + //------------------------------------------------------------------------- + + /** + * Read the entity instance of the given class with the given id, + * throwing an exception if not found. + *

Retrieves read-write objects from the TopLink UnitOfWork in case of a + * non-read-only transaction, and read-only objects else. + * @param entityClass the entity class + * @param id the id of the desired object + * @return the entity instance + * @throws org.springframework.orm.ObjectRetrievalFailureException if not found + * @throws org.springframework.dao.DataAccessException in case of TopLink errors + * @see oracle.toplink.queryframework.ReadObjectQuery#setSelectionKey(java.util.Vector) + */ + Object readById(Class entityClass, Object id) throws DataAccessException; + + /** + * Read the entity instance of the given class with the given id, + * throwing an exception if not found. + * @param entityClass the entity class + * @param id the id of the desired object + * @return the entity instance + * @param enforceReadOnly whether to always retrieve read-only objects from + * the plain TopLink Session (else, read-write objects will be retrieved + * from the TopLink UnitOfWork in case of a non-read-only transaction) + * @throws org.springframework.orm.ObjectRetrievalFailureException if not found + * @throws org.springframework.dao.DataAccessException in case of TopLink errors + * @see oracle.toplink.queryframework.ReadObjectQuery#setSelectionKey(java.util.Vector) + */ + Object readById(Class entityClass, Object id, boolean enforceReadOnly) throws DataAccessException; + + /** + * Read the entity instance of the given class with the given composite id, + * throwing an exception if not found. + *

Retrieves read-write objects from the TopLink UnitOfWork in case of a + * non-read-only transaction, and read-only objects else. + * @param entityClass the entity class + * @param keys the composite id elements of the desired object + * @return the entity instance + * @throws org.springframework.orm.ObjectRetrievalFailureException if not found + * @throws org.springframework.dao.DataAccessException in case of TopLink errors + * @see oracle.toplink.queryframework.ReadObjectQuery#setSelectionKey(java.util.Vector) + */ + Object readById(Class entityClass, Object[] keys) throws DataAccessException; + + /** + * Read the entity instance of the given class with the given composite id, + * throwing an exception if not found. + * @param entityClass the entity class + * @param keys the composite id elements of the desired object + * @param enforceReadOnly whether to always retrieve read-only objects from + * the plain TopLink Session (else, read-write objects will be retrieved + * from the TopLink UnitOfWork in case of a non-read-only transaction) + * @return the entity instance + * @throws org.springframework.orm.ObjectRetrievalFailureException if not found + * @throws org.springframework.dao.DataAccessException in case of TopLink errors + * @see oracle.toplink.queryframework.ReadObjectQuery#setSelectionKey(java.util.Vector) + */ + Object readById(Class entityClass, Object[] keys, boolean enforceReadOnly) throws DataAccessException; + + /** + * Read the entity instance of the given class with the given id, + * throwing an exception if not found. A detached copy of the entity object + * will be returned, allowing for modifications outside the current transaction, + * with the changes to be merged into a later transaction. + *

Retrieves read-write objects from the TopLink UnitOfWork in case of a + * non-read-only transaction, and read-only objects else. + * @param entityClass the entity class + * @param id the id of the desired object + * @return a copy of the entity instance + * @throws org.springframework.orm.ObjectRetrievalFailureException if not found + * @throws org.springframework.dao.DataAccessException in case of TopLink errors + * @see oracle.toplink.queryframework.ReadObjectQuery#setSelectionKey(java.util.Vector) + * @see oracle.toplink.sessions.Session#copyObject(Object) + */ + Object readAndCopy(Class entityClass, Object id) throws DataAccessException; + + /** + * Read the entity instance of the given class with the given id, + * throwing an exception if not found. A detached copy of the entity object + * will be returned, allowing for modifications outside the current transaction, + * with the changes to be merged into a later transaction. + * @param entityClass the entity class + * @param id the id of the desired object + * @param enforceReadOnly whether to always retrieve read-only objects from + * the plain TopLink Session (else, read-write objects will be retrieved + * from the TopLink UnitOfWork in case of a non-read-only transaction) + * @return a copy of the entity instance + * @throws org.springframework.orm.ObjectRetrievalFailureException if not found + * @throws org.springframework.dao.DataAccessException in case of TopLink errors + * @see oracle.toplink.queryframework.ReadObjectQuery#setSelectionKey(java.util.Vector) + * @see oracle.toplink.sessions.Session#copyObject(Object) + */ + Object readAndCopy(Class entityClass, Object id, boolean enforceReadOnly) throws DataAccessException; + + /** + * Read the entity instance of the given class with the given composite id, + * throwing an exception if not found. A detached copy of the entity object + * will be returned, allowing for modifications outside the current transaction, + * with the changes to be merged into a later transaction. + *

Retrieves read-write objects from the TopLink UnitOfWork in case of a + * non-read-only transaction, and read-only objects else. + * @param entityClass the entity class + * @param keys the composite id elements of the desired object + * @return a copy of the entity instance + * @throws org.springframework.orm.ObjectRetrievalFailureException if not found + * @throws org.springframework.dao.DataAccessException in case of TopLink errors + * @see oracle.toplink.queryframework.ReadObjectQuery#setSelectionKey(java.util.Vector) + * @see oracle.toplink.sessions.Session#copyObject(Object) + */ + Object readAndCopy(Class entityClass, Object[] keys) throws DataAccessException; + + /** + * Read the entity instance of the given class with the given composite id, + * throwing an exception if not found. A detached copy of the entity object + * will be returned, allowing for modifications outside the current transaction, + * with the changes to be merged into a later transaction. + * @param entityClass the entity class + * @param keys the composite id elements of the desired object + * @param enforceReadOnly whether to always retrieve read-only objects from + * the plain TopLink Session (else, read-write objects will be retrieved + * from the TopLink UnitOfWork in case of a non-read-only transaction) + * @return a copy of the entity instance + * @throws org.springframework.orm.ObjectRetrievalFailureException if not found + * @throws org.springframework.dao.DataAccessException in case of TopLink errors + * @see oracle.toplink.queryframework.ReadObjectQuery#setSelectionKey(java.util.Vector) + * @see oracle.toplink.sessions.Session#copyObject(Object) + */ + Object readAndCopy(Class entityClass, Object[] keys, boolean enforceReadOnly) throws DataAccessException; + + + //------------------------------------------------------------------------- + // Convenience methods for copying and refreshing objects + //------------------------------------------------------------------------- + + /** + * Create a detached copy of the given entity object, + * using TopLink's default ObjectCopyingPolicy. + * @param entity the entity object to copy + * @return the copy of the entity object + * @throws org.springframework.dao.DataAccessException in case of TopLink errors + * @see oracle.toplink.sessions.Session#copyObject(Object) + */ + Object copy(Object entity) throws DataAccessException; + + /** + * Create a detached copy of the given entity object. + * @param entity the entity object to copy + * @param copyingPolicy the TopLink ObjectCopyingPolicy to apply + * @return the copy of the entity object + * @throws org.springframework.dao.DataAccessException in case of TopLink errors + * @see oracle.toplink.sessions.Session#copyObject(Object, oracle.toplink.sessions.ObjectCopyingPolicy) + */ + Object copy(Object entity, ObjectCopyingPolicy copyingPolicy) throws DataAccessException; + + /** + * Create detached copies of all given entity objects, + * using TopLink's default ObjectCopyingPolicy. + * @param entities the entity objects to copy + * @return the copies of the entity objects + * @throws org.springframework.dao.DataAccessException in case of TopLink errors + * @see oracle.toplink.sessions.Session#copyObject(Object) + */ + List copyAll(Collection entities) throws DataAccessException; + + /** + * Create detached copies of all given entity objects. + * @param entities the entity objects to copy + * @param copyingPolicy the TopLink ObjectCopyingPolicy to apply + * @return the copies of the entity objects + * @throws org.springframework.dao.DataAccessException in case of TopLink errors + * @see oracle.toplink.sessions.Session#copyObject(Object) + */ + List copyAll(Collection entities, ObjectCopyingPolicy copyingPolicy) throws DataAccessException; + + /** + * Refresh the given entity object, returning the refreshed object. + *

The returned object will only be different from the passed-in object + * if the passed-in object is not the currently registered version of + * the corresponding entity. + *

Retrieves read-write objects from the TopLink UnitOfWork in case of a + * non-read-only transaction, and read-only objects else. + * @param entity the entity object to refresh + * @return the refreshed version of the entity object + * @throws org.springframework.dao.DataAccessException in case of TopLink errors + * @see oracle.toplink.sessions.Session#refreshObject(Object) + */ + Object refresh(Object entity) throws DataAccessException; + + /** + * Refresh the given entity object, returning the refreshed object. + *

The returned object will only be different from the passed-in object + * if the passed-in object is not the currently registered version of + * the corresponding entity. + *

Retrieves read-write objects from the TopLink UnitOfWork in case of a + * non-read-only transaction, and read-only objects else. + * @param entity the entity object to refresh + * @param enforceReadOnly whether to always retrieve read-only objects from + * the plain TopLink Session (else, read-write objects will be retrieved + * from the TopLink UnitOfWork in case of a non-read-only transaction) + * @return the refreshed version of the entity object + * @throws org.springframework.dao.DataAccessException in case of TopLink errors + * @see oracle.toplink.sessions.Session#refreshObject(Object) + */ + Object refresh(Object entity, boolean enforceReadOnly) throws DataAccessException; + + /** + * Refresh the given entity objects, returning the corresponding refreshed objects. + *

A returned object will only be different from the corresponding passed-in + * object if the passed-in object is not the currently registered version of + * the corresponding entity. + *

Retrieves read-write objects from the TopLink UnitOfWork in case of a + * non-read-only transaction, and read-only objects else. + * @param entities the entity objects to refresh + * @return the refreshed versions of the entity objects + * @throws org.springframework.dao.DataAccessException in case of TopLink errors + * @see oracle.toplink.sessions.Session#refreshObject(Object) + */ + List refreshAll(Collection entities) throws DataAccessException; + + /** + * Refresh the given entity objects, returning the corresponding refreshed objects. + *

A returned object will only be different from the corresponding passed-in + * object if the passed-in object is not the currently registered version of + * the corresponding entity. + * @param entities the entity objects to refresh + * @param enforceReadOnly whether to always retrieve read-only objects from + * the plain TopLink Session (else, read-write objects will be retrieved + * from the TopLink UnitOfWork in case of a non-read-only transaction) + * @return the refreshed versions of the entity objects + * @throws org.springframework.dao.DataAccessException in case of TopLink errors + * @see oracle.toplink.sessions.Session#refreshObject(Object) + */ + List refreshAll(Collection entities, boolean enforceReadOnly) throws DataAccessException; + + + //------------------------------------------------------------------------- + // Convenience methods for persisting and deleting objects + //------------------------------------------------------------------------- + + /** + * Register the given (new or existing) entity with the current UnitOfWork. + *

The entity will be checked for existence, according to TopLink's + * configured existence checking policy. To avoid the (potentially costly) + * existence check, consider using the specific registerNew + * or registerExisting method. + * Do not edit the passed-in object any further afterwards. + * @param entity the entity to register + * @return the registered clone of the original object, + * which needs to be used for further editing + * @throws org.springframework.dao.DataAccessException in case of TopLink errors + * @see oracle.toplink.sessions.UnitOfWork#registerObject(Object) + * @see #registerNew(Object) + * @see #registerExisting(Object) + */ + Object register(Object entity); + + /** + * Register all given entities with the current UnitOfWork. + * Do not edit the passed-in objects any further afterwards. + * @param entities the entities to register + * @return the registered clones of the original objects, + * which need to be used for further editing + * @throws org.springframework.dao.DataAccessException in case of TopLink errors + * @see oracle.toplink.sessions.UnitOfWork#registerAllObjects(java.util.Collection) + */ + List registerAll(Collection entities); + + /** + * Register the given new entity with the current UnitOfWork. + * The passed-in object can be edited further afterwards. + * @param entity the new entity to register + * @throws org.springframework.dao.DataAccessException in case of TopLink errors + * @see oracle.toplink.sessions.UnitOfWork#registerNewObject(Object) + */ + void registerNew(Object entity); + + /** + * Register the given existing entity with the current UnitOfWork. + * Do not edit the passed-in object any further afterwards. + * @param entity the existing entity to register + * @return the registered clone of the original object, + * which needs to be used for further editing + * @throws org.springframework.dao.DataAccessException in case of TopLink errors + * @see oracle.toplink.sessions.UnitOfWork#registerExistingObject(Object) + */ + Object registerExisting(Object entity); + + /** + * Reassociate the given entity copy with the current UnitOfWork, + * using simple merging. + *

The given object will not be reassociated itself: instead, the state + * will be copied onto the persistent object with the same identifier. + * In case of a new entity, merge will copy to a registered object as well, + * but will also update the identifier of the passed-in object. + * @param entity the updated copy to merge + * @return the updated, registered persistent instance + * @throws org.springframework.dao.DataAccessException in case of TopLink errors + * @see oracle.toplink.sessions.UnitOfWork#mergeClone(Object) + */ + Object merge(Object entity) throws DataAccessException; + + /** + * Reassociate the given entity copy with the current UnitOfWork, + * using deep merging of all contained entities. + *

The given object will not be reassociated itself: instead, the state + * will be copied onto the persistent object with the same identifier. + * In case of a new entity, merge will register a copy as well, + * but will also update the identifier of the passed-in object. + * @param entity the updated copy to merge + * @return the updated, registered persistent instance + * @throws org.springframework.dao.DataAccessException in case of TopLink errors + * @see oracle.toplink.sessions.UnitOfWork#deepMergeClone(Object) + */ + Object deepMerge(Object entity) throws DataAccessException; + + /** + * Reassociate the given entity copy with the current UnitOfWork, + * using shallow merging of the entity instance. + *

The given object will not be reassociated itself: instead, the state + * will be copied onto the persistent object with the same identifier. + * In case of a new entity, merge will register a copy as well, + * but will also update the identifier of the passed-in object. + * @param entity the updated copy to merge + * @return the updated, registered persistent instance + * @throws org.springframework.dao.DataAccessException in case of TopLink errors + * @see oracle.toplink.sessions.UnitOfWork#shallowMergeClone(Object) + */ + Object shallowMerge(Object entity) throws DataAccessException; + + /** + * Reassociate the given entity copy with the current UnitOfWork, + * using merging with all references from this clone. + *

The given object will not be reassociated itself: instead, the state + * will be copied onto the persistent object with the same identifier. + * In case of a new entity, merge will register a copy as well, + * but will also update the identifier of the passed-in object. + * @param entity the updated copy to merge + * @return the updated, registered persistent instance + * @throws org.springframework.dao.DataAccessException in case of TopLink errors + * @see oracle.toplink.sessions.UnitOfWork#mergeCloneWithReferences(Object) + */ + Object mergeWithReferences(Object entity) throws DataAccessException; + + /** + * Delete the given entity. + * @param entity the entity to delete + * @throws org.springframework.dao.DataAccessException in case of TopLink errors + * @see oracle.toplink.sessions.UnitOfWork#deleteObject(Object) + */ + void delete(Object entity) throws DataAccessException; + + /** + * Delete all given entities. + * @param entities the entities to delete + * @throws org.springframework.dao.DataAccessException in case of TopLink errors + * @see oracle.toplink.sessions.UnitOfWork#deleteAllObjects(java.util.Collection) + */ + void deleteAll(Collection entities) throws DataAccessException; + +} Index: 3rdParty_sources/spring/org/springframework/orm/toplink/TopLinkOptimisticLockingFailureException.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/toplink/TopLinkOptimisticLockingFailureException.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/orm/toplink/TopLinkOptimisticLockingFailureException.java 17 Aug 2012 15:16:11 -0000 1.1 @@ -0,0 +1,36 @@ +/* + * 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.toplink; + +import oracle.toplink.exceptions.OptimisticLockException; + +import org.springframework.orm.ObjectOptimisticLockingFailureException; + +/** + * TopLink-specific subclass of ObjectOptimisticLockingFailureException. + * Converts TopLink's OptimisticLockException. + * + * @author Juergen Hoeller + * @since 1.2 + */ +public class TopLinkOptimisticLockingFailureException extends ObjectOptimisticLockingFailureException { + + public TopLinkOptimisticLockingFailureException(OptimisticLockException ex) { + super(ex.getObject() != null ? ex.getObject().getClass() : null, null, ex.getMessage(), ex); + } + +} Index: 3rdParty_sources/spring/org/springframework/orm/toplink/TopLinkQueryException.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/toplink/TopLinkQueryException.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/orm/toplink/TopLinkQueryException.java 17 Aug 2012 15:16:11 -0000 1.1 @@ -0,0 +1,36 @@ +/* + * 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.toplink; + +import oracle.toplink.exceptions.QueryException; + +import org.springframework.dao.InvalidDataAccessResourceUsageException; + +/** + * TopLink-specific subclass of InvalidDataAccessResourceUsageException, + * thrown on invalid TopLink query syntax or behavior. + * + * @author Juergen Hoeller + * @since 1.2 + */ +public class TopLinkQueryException extends InvalidDataAccessResourceUsageException { + + public TopLinkQueryException(QueryException ex) { + super(ex.getMessage(), ex); + } + +} Index: 3rdParty_sources/spring/org/springframework/orm/toplink/TopLinkSystemException.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/toplink/TopLinkSystemException.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/orm/toplink/TopLinkSystemException.java 17 Aug 2012 15:16:11 -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.toplink; + +import oracle.toplink.exceptions.TopLinkException; + +import org.springframework.dao.UncategorizedDataAccessException; + +/** + * TopLink-specific subclass of UncategorizedDataAccessException, + * for TopLink system errors that do not match any concrete + * org.springframework.dao exceptions. + * + * @author Juergen Hoeller + * @since 1.2 + * @see SessionFactoryUtils#convertTopLinkAccessException + */ +public class TopLinkSystemException extends UncategorizedDataAccessException { + + public TopLinkSystemException(TopLinkException ex) { + super(ex.getMessage(), ex); + } + +} Index: 3rdParty_sources/spring/org/springframework/orm/toplink/TopLinkTemplate.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/toplink/TopLinkTemplate.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/orm/toplink/TopLinkTemplate.java 17 Aug 2012 15:16:11 -0000 1.1 @@ -0,0 +1,515 @@ +/* + * 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.toplink; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import java.util.Vector; + +import oracle.toplink.exceptions.TopLinkException; +import oracle.toplink.expressions.Expression; +import oracle.toplink.queryframework.Call; +import oracle.toplink.queryframework.DatabaseQuery; +import oracle.toplink.queryframework.ReadObjectQuery; +import oracle.toplink.sessions.ObjectCopyingPolicy; +import oracle.toplink.sessions.Session; +import oracle.toplink.sessions.UnitOfWork; + +import org.springframework.dao.DataAccessException; +import org.springframework.dao.InvalidDataAccessApiUsageException; +import org.springframework.orm.ObjectRetrievalFailureException; +import org.springframework.util.Assert; +import org.springframework.util.StringUtils; + +/** + * Helper class that simplifies TopLink data access code, and converts + * TopLinkExceptions into unchecked DataAccessExceptions, following the + * org.springframework.dao exception hierarchy. + * + *

The central method is execute, supporting TopLink access code + * implementing the {@link TopLinkCallback} interface. It provides TopLink Session + * handling such that neither the TopLinkCallback implementation nor the calling + * code needs to explicitly care about retrieving/closing TopLink Sessions, + * or handling Session lifecycle exceptions. For typical single step actions, + * there are various convenience methods (read, readAll, merge, delete, etc). + * + *

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. + * + *

This class can be considered as direct alternative to working with the raw + * TopLink Session API (through SessionFactoryUtils.getSession()). + * 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 LocalSessionFactoryBean} is the preferred way of obtaining a reference + * to a specific TopLink SessionFactory. It will usually be configured to + * create ClientSessions for a ServerSession held by it, allowing for seamless + * multi-threaded execution. The Spring application context will manage its lifecycle, + * initializing and shutting down the factory as part of the application. + * + *

Thanks to Slavik Markovich for implementing the initial TopLink support prototype! + * + * @author Juergen Hoeller + * @author James Clark + * @since 1.2 + * @see #setSessionFactory + * @see TopLinkCallback + * @see oracle.toplink.sessions.Session + * @see TopLinkInterceptor + * @see LocalSessionFactoryBean + * @see TopLinkTransactionManager + * @see org.springframework.transaction.jta.JtaTransactionManager + */ +public class TopLinkTemplate extends TopLinkAccessor implements TopLinkOperations { + + private boolean allowCreate = true; + + + /** + * Create a new TopLinkTemplate instance. + */ + public TopLinkTemplate() { + } + + /** + * Create a new TopLinkTemplate instance. + */ + public TopLinkTemplate(SessionFactory sessionFactory) { + setSessionFactory(sessionFactory); + afterPropertiesSet(); + } + + /** + * Create a new TopLinkTemplate instance. + * @param allowCreate if a new Session should be created if no thread-bound found + */ + public TopLinkTemplate(SessionFactory sessionFactory, boolean allowCreate) { + setSessionFactory(sessionFactory); + setAllowCreate(allowCreate); + afterPropertiesSet(); + } + + /** + * Set if a new Session should be created when no transactional Session + * can be found for the current thread. + *

TopLinkTemplate is aware of a corresponding Session bound to the + * current thread, for example when using TopLinkTransactionManager. + * If allowCreate is true, a new non-transactional Session 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 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; + } + + + public Object execute(TopLinkCallback action) throws DataAccessException { + Assert.notNull(action, "Callback object must not be null"); + + Session session = SessionFactoryUtils.getSession(getSessionFactory(), this.allowCreate); + try { + return action.doInTopLink(session); + } + catch (TopLinkException ex) { + throw convertTopLinkAccessException(ex); + } + catch (RuntimeException ex) { + // callback code threw application exception + throw ex; + } + finally { + SessionFactoryUtils.releaseSession(session, getSessionFactory()); + } + } + + public List executeFind(TopLinkCallback action) throws DataAccessException { + Object result = execute(action); + if (result != null && !(result instanceof List)) { + throw new InvalidDataAccessApiUsageException( + "Result object returned from TopLinkCallback isn't a List: [" + result + "]"); + } + return (List) result; + } + + + //------------------------------------------------------------------------- + // Convenience methods for executing generic queries + //------------------------------------------------------------------------- + + public Object executeNamedQuery(Class entityClass, String queryName) throws DataAccessException { + return executeNamedQuery(entityClass, queryName, null, false); + } + + public Object executeNamedQuery(Class entityClass, String queryName, boolean enforceReadOnly) + throws DataAccessException { + + return executeNamedQuery(entityClass, queryName, null, enforceReadOnly); + } + + public Object executeNamedQuery(Class entityClass, String queryName, Object[] args) + throws DataAccessException { + + return executeNamedQuery(entityClass, queryName, args, false); + } + + public Object executeNamedQuery( + final Class entityClass, final String queryName, final Object[] args, final boolean enforceReadOnly) + throws DataAccessException { + + return execute(new SessionReadCallback(enforceReadOnly) { + protected Object readFromSession(Session session) throws TopLinkException { + if (args != null) { + return session.executeQuery(queryName, entityClass, new Vector(Arrays.asList(args))); + } + else { + return session.executeQuery(queryName, entityClass, new Vector()); + } + } + }); + } + + public Object executeQuery(DatabaseQuery query) throws DataAccessException { + return executeQuery(query, null, false); + } + + public Object executeQuery(DatabaseQuery query, boolean enforceReadOnly) throws DataAccessException { + return executeQuery(query, null, enforceReadOnly); + } + + public Object executeQuery(DatabaseQuery query, Object[] args) throws DataAccessException { + return executeQuery(query, args, false); + } + + public Object executeQuery(final DatabaseQuery query, final Object[] args, final boolean enforceReadOnly) + throws DataAccessException { + + return execute(new SessionReadCallback(enforceReadOnly) { + protected Object readFromSession(Session session) throws TopLinkException { + if (args != null) { + return session.executeQuery(query, new Vector(Arrays.asList(args))); + } + else { + return session.executeQuery(query); + } + } + }); + } + + + //------------------------------------------------------------------------- + // Convenience methods for reading a specific set of objects + //------------------------------------------------------------------------- + + public List readAll(Class entityClass) throws DataAccessException { + return readAll(entityClass, false); + } + + public List readAll(final Class entityClass, final boolean enforceReadOnly) throws DataAccessException { + return executeFind(new SessionReadCallback(enforceReadOnly) { + protected Object readFromSession(Session session) throws TopLinkException { + return session.readAllObjects(entityClass); + } + }); + } + + public List readAll(Class entityClass, Expression expression) throws DataAccessException { + return readAll(entityClass, expression, false); + } + + public List readAll(final Class entityClass, final Expression expression, final boolean enforceReadOnly) + throws DataAccessException { + + return executeFind(new SessionReadCallback(enforceReadOnly) { + protected Object readFromSession(Session session) throws TopLinkException { + return session.readAllObjects(entityClass, expression); + } + }); + } + + public List readAll(Class entityClass, Call call) throws DataAccessException { + return readAll(entityClass, call, false); + } + + public List readAll(final Class entityClass, final Call call, final boolean enforceReadOnly) + throws DataAccessException { + + return executeFind(new SessionReadCallback(enforceReadOnly) { + protected Object readFromSession(Session session) throws TopLinkException { + return session.readAllObjects(entityClass, call); + } + }); + } + + public Object read(Class entityClass, Expression expression) throws DataAccessException { + return read(entityClass, expression, false); + } + + public Object read(final Class entityClass, final Expression expression, final boolean enforceReadOnly) + throws DataAccessException { + + return execute(new SessionReadCallback(enforceReadOnly) { + protected Object readFromSession(Session session) throws TopLinkException { + return session.readObject(entityClass, expression); + } + }); + } + + public Object read(Class entityClass, Call call) throws DataAccessException { + return read(entityClass, call, false); + } + + public Object read(final Class entityClass, final Call call, final boolean enforceReadOnly) + throws DataAccessException { + + return execute(new SessionReadCallback(enforceReadOnly) { + protected Object readFromSession(Session session) throws TopLinkException { + return session.readObject(entityClass, call); + } + }); + } + + + //------------------------------------------------------------------------- + // Convenience methods for reading an individual object by id + //------------------------------------------------------------------------- + + public Object readById(Class entityClass, Object id) throws DataAccessException { + return readById(entityClass, id, false); + } + + public Object readById(Class entityClass, Object id, boolean enforceReadOnly) throws DataAccessException { + return readById(entityClass, new Object[] {id}, enforceReadOnly); + } + + public Object readById(Class entityClass, Object[] keys) throws DataAccessException { + return readById(entityClass, keys, false); + } + + public Object readById(final Class entityClass, final Object[] keys, final boolean enforceReadOnly) + throws DataAccessException { + + Assert.isTrue(keys != null && keys.length > 0, "Non-empty keys or id is required"); + + ReadObjectQuery query = new ReadObjectQuery(entityClass); + query.setSelectionKey(new Vector(Arrays.asList(keys))); + Object result = executeQuery(query, enforceReadOnly); + + if (result == null) { + Object identifier = (keys.length == 1 ? keys[0] : StringUtils.arrayToCommaDelimitedString(keys)); + throw new ObjectRetrievalFailureException(entityClass, identifier); + } + return result; + } + + public Object readAndCopy(Class entityClass, Object id) throws DataAccessException { + return readAndCopy(entityClass, id, false); + } + + public Object readAndCopy(Class entityClass, Object id, boolean enforceReadOnly) + throws DataAccessException { + + Object entity = readById(entityClass, id, enforceReadOnly); + return copy(entity); + } + + public Object readAndCopy(Class entityClass, Object[] keys) throws DataAccessException { + return readAndCopy(entityClass, keys, false); + } + + public Object readAndCopy(Class entityClass, Object[] keys, boolean enforceReadOnly) + throws DataAccessException { + + Object entity = readById(entityClass, keys, enforceReadOnly); + return copy(entity); + } + + + //------------------------------------------------------------------------- + // Convenience methods for copying and refreshing objects + //------------------------------------------------------------------------- + + public Object copy(Object entity) throws DataAccessException { + ObjectCopyingPolicy copyingPolicy = new ObjectCopyingPolicy(); + copyingPolicy.cascadeAllParts(); + copyingPolicy.setShouldResetPrimaryKey(false); + return copy(entity, copyingPolicy); + } + + public Object copy(final Object entity, final ObjectCopyingPolicy copyingPolicy) + throws DataAccessException { + + return execute(new TopLinkCallback() { + public Object doInTopLink(Session session) throws TopLinkException { + return session.copyObject(entity, copyingPolicy); + } + }); + } + + public List copyAll(Collection entities) throws DataAccessException { + ObjectCopyingPolicy copyingPolicy = new ObjectCopyingPolicy(); + copyingPolicy.cascadeAllParts(); + copyingPolicy.setShouldResetPrimaryKey(false); + return copyAll(entities, copyingPolicy); + } + + public List copyAll(final Collection entities, final ObjectCopyingPolicy copyingPolicy) + throws DataAccessException { + + return (List) execute(new TopLinkCallback() { + public Object doInTopLink(Session session) throws TopLinkException { + List result = new ArrayList(entities.size()); + for (Iterator it = entities.iterator(); it.hasNext();) { + Object entity = it.next(); + result.add(session.copyObject(entity, copyingPolicy)); + } + return result; + } + }); + } + + public Object refresh(Object entity) throws DataAccessException { + return refresh(entity, false); + } + + public Object refresh(final Object entity, final boolean enforceReadOnly) throws DataAccessException { + return execute(new SessionReadCallback(enforceReadOnly) { + protected Object readFromSession(Session session) throws TopLinkException { + return session.refreshObject(entity); + } + }); + } + + public List refreshAll(Collection entities) throws DataAccessException { + return refreshAll(entities, false); + } + + public List refreshAll(final Collection entities, final boolean enforceReadOnly) throws DataAccessException { + return (List) execute(new SessionReadCallback(enforceReadOnly) { + protected Object readFromSession(Session session) throws TopLinkException { + List result = new ArrayList(entities.size()); + for (Iterator it = entities.iterator(); it.hasNext();) { + Object entity = it.next(); + result.add(session.refreshObject(entity)); + } + return result; + } + }); + } + + + //------------------------------------------------------------------------- + // Convenience methods for persisting and deleting objects + //------------------------------------------------------------------------- + + public Object register(final Object entity) { + return execute(new UnitOfWorkCallback() { + protected Object doInUnitOfWork(UnitOfWork unitOfWork) throws TopLinkException { + return unitOfWork.registerObject(entity); + } + }); + } + + public List registerAll(final Collection entities) { + return (List) execute(new UnitOfWorkCallback() { + protected Object doInUnitOfWork(UnitOfWork unitOfWork) throws TopLinkException { + return unitOfWork.registerAllObjects(entities); + } + }); + } + + public void registerNew(final Object entity) { + execute(new UnitOfWorkCallback() { + protected Object doInUnitOfWork(UnitOfWork unitOfWork) throws TopLinkException { + return unitOfWork.registerNewObject(entity); + } + }); + } + + public Object registerExisting(final Object entity) { + return execute(new UnitOfWorkCallback() { + protected Object doInUnitOfWork(UnitOfWork unitOfWork) throws TopLinkException { + return unitOfWork.registerExistingObject(entity); + } + }); + } + + public Object merge(final Object entity) throws DataAccessException { + return execute(new UnitOfWorkCallback() { + protected Object doInUnitOfWork(UnitOfWork unitOfWork) throws TopLinkException { + return unitOfWork.mergeClone(entity); + } + }); + } + + public Object deepMerge(final Object entity) throws DataAccessException { + return execute(new UnitOfWorkCallback() { + protected Object doInUnitOfWork(UnitOfWork unitOfWork) throws TopLinkException { + return unitOfWork.deepMergeClone(entity); + } + }); + } + + public Object shallowMerge(final Object entity) throws DataAccessException { + return execute(new UnitOfWorkCallback() { + protected Object doInUnitOfWork(UnitOfWork unitOfWork) throws TopLinkException { + return unitOfWork.shallowMergeClone(entity); + } + }); + } + + public Object mergeWithReferences(final Object entity) throws DataAccessException { + return execute(new UnitOfWorkCallback() { + protected Object doInUnitOfWork(UnitOfWork unitOfWork) throws TopLinkException { + return unitOfWork.mergeCloneWithReferences(entity); + } + }); + } + + public void delete(final Object entity) throws DataAccessException { + execute(new UnitOfWorkCallback() { + protected Object doInUnitOfWork(UnitOfWork unitOfWork) throws TopLinkException { + return unitOfWork.deleteObject(entity); + } + }); + } + + public void deleteAll(final Collection entities) throws DataAccessException { + execute(new UnitOfWorkCallback() { + protected Object doInUnitOfWork(UnitOfWork unitOfWork) throws TopLinkException { + unitOfWork.deleteAllObjects(entities); + return null; + } + }); + } + +} Index: 3rdParty_sources/spring/org/springframework/orm/toplink/TopLinkTransactionManager.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/toplink/TopLinkTransactionManager.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/orm/toplink/TopLinkTransactionManager.java 17 Aug 2012 15:16:11 -0000 1.1 @@ -0,0 +1,480 @@ +/* + * 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.toplink; + +import java.sql.Connection; +import java.sql.SQLException; + +import javax.sql.DataSource; + +import oracle.toplink.exceptions.DatabaseException; +import oracle.toplink.exceptions.TopLinkException; +import oracle.toplink.internal.databaseaccess.Accessor; +import oracle.toplink.internal.databaseaccess.DatabaseAccessor; +import oracle.toplink.sessions.Session; + +import org.springframework.beans.factory.InitializingBean; +import org.springframework.dao.DataAccessException; +import org.springframework.jdbc.datasource.ConnectionHolder; +import org.springframework.jdbc.datasource.JdbcTransactionObjectSupport; +import org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy; +import org.springframework.jdbc.support.SQLExceptionTranslator; +import org.springframework.transaction.CannotCreateTransactionException; +import org.springframework.transaction.TransactionDefinition; +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 TopLink {@link SessionFactory}. Binds a TopLink Session from the + * specified factory to the thread, potentially allowing for one thread-bound Session + * per factory. {@link SessionFactoryUtils} and {@link TopLinkTemplate} are aware + * of thread-bound Sessions and participate in such transactions automatically. + * Using either of those or going through Session.getActiveUnitOfWork() is + * required for TopLink access code supporting this transaction handling mechanism. + * + *

This transaction manager is appropriate for applications that use a single + * TopLink SessionFactory 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 TopLink with an appropriate external transaction + * controller 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), but only for transactions + * that are not marked as read-only. This allows for mixing services which + * access TopLink and services which use plain JDBC (without being aware of TopLink)! + * 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 TopLink + * SessionFactory. + * + *

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 TopLink 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 TopLink transactions (provided that + * your JDBC driver supports Savepoints). Note that TopLink itself does not + * support nested transactions! Hence, do not expect TopLink access code to + * semantically participate in a nested transaction. + * + *

Thanks to Slavik Markovich for implementing the initial TopLink support prototype! + * + * @author Juergen Hoeller + * @author James Clark + * @since 1.2 + * @see #setSessionFactory + * @see #setDataSource + * @see LocalSessionFactoryBean + * @see SessionFactoryUtils#getSession + * @see SessionFactoryUtils#releaseSession + * @see TopLinkTemplate + * @see oracle.toplink.sessions.Session#getActiveUnitOfWork() + * @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 TopLinkTransactionManager extends AbstractPlatformTransactionManager + implements ResourceTransactionManager, InitializingBean { + + private SessionFactory sessionFactory; + + private DataSource dataSource; + + private boolean lazyDatabaseTransaction = false; + + private SQLExceptionTranslator jdbcExceptionTranslator; + + + /** + * Create a new TopLinkTransactionManager instance. + * A SessionFactory has to be specified to be able to use it. + * @see #setSessionFactory + */ + public TopLinkTransactionManager() { + } + + /** + * Create a new TopLinkTransactionManager instance. + * @param sessionFactory the TopLink SessionFactory to manage transactions for + */ + public TopLinkTransactionManager(SessionFactory sessionFactory) { + this.sessionFactory = sessionFactory; + afterPropertiesSet(); + } + + /** + * Set the the TopLink SessionFactory to manage transactions for. + * This will usually be a ServerSessionFactory. + *

The passed-in SessionFactory will be asked for a plain Session + * in case of a read-only transaction (where no active UnitOfWork is + * supposed to be available), and for a managed Session else (with an + * active UnitOfWork that will be committed by this transaction manager). + * @see ServerSessionFactory + * @see SessionFactory#createSession() + * @see SessionFactory#createManagedClientSession() + */ + 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 TopLink SessionFactory: + * for example, you could specify the same JNDI DataSource for both. + *

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 TopLink Session. + * This will only happen for transactions that are not marked + * as read-only. TopLink does not support database transactions for pure + * read-only operations on a Session (that is, without a UnitOfWork). + *

Note that you need to use a TopLink Session with a DatabaseAccessor + * to allow for exposing TopLink transactions as JDBC transactions. This is + * the case of all standard TopLink configurations. + *

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 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 lazily start a database transaction within a TopLink + * transaction. + *

By default, database transactions are started early. This allows + * for reusing the same JDBC Connection throughout an entire transaction, + * including read operations, and also for exposing TopLink transactions + * to JDBC access code (working on the same DataSource). + *

It is only recommended to switch this flag to "true" when no JDBC access + * code is involved in any of the transactions, and when it is acceptable to + * perform read operations outside of the transactional JDBC Connection. + * @see #setDataSource(javax.sql.DataSource) + * @see oracle.toplink.sessions.UnitOfWork#beginEarlyTransaction() + */ + public void setLazyDatabaseTransaction(boolean lazyDatabaseTransaction) { + this.lazyDatabaseTransaction = lazyDatabaseTransaction; + } + + /** + * Return whether to lazily start a database transaction within a TopLink + * transaction. + */ + public boolean isLazyDatabaseTransaction() { + return this.lazyDatabaseTransaction; + } + + /** + * Set the JDBC exception translator for this transaction manager. + *

Applied to any SQLException root cause of a TopLink DatabaseException + * that is thrown on commit. The default is to rely on TopLink's native + * exception translation. + * @param jdbcExceptionTranslator the exception translator + * @see oracle.toplink.exceptions.DatabaseException + * @see org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator + * @see org.springframework.jdbc.support.SQLStateSQLExceptionTranslator + * @see #setDataSource(javax.sql.DataSource) + */ + 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; + } + + public void afterPropertiesSet() { + if (getSessionFactory() == null) { + throw new IllegalArgumentException("Property 'sessionFactory' is required"); + } + } + + + public Object getResourceFactory() { + return getSessionFactory(); + } + + protected Object doGetTransaction() { + TopLinkTransactionObject txObject = new TopLinkTransactionObject(); + SessionHolder sessionHolder = (SessionHolder) + TransactionSynchronizationManager.getResource(this.sessionFactory); + txObject.setSessionHolder(sessionHolder); + return txObject; + } + + protected boolean isExistingTransaction(Object transaction) { + TopLinkTransactionObject txObject = (TopLinkTransactionObject) transaction; + return (txObject.getSessionHolder() != null); + } + + protected void doBegin(Object transaction, TransactionDefinition definition) { + Session session = null; + + try { + if (!definition.isReadOnly()) { + logger.debug("Creating managed TopLink Session with active UnitOfWork for read-write transaction"); + session = getSessionFactory().createManagedClientSession(); + } + else { + logger.debug("Creating plain TopLink Session without active UnitOfWork for read-only transaction"); + session = getSessionFactory().createSession(); + } + + if (logger.isDebugEnabled()) { + logger.debug("Opened new session [" + session + "] for TopLink transaction"); + } + + TopLinkTransactionObject txObject = (TopLinkTransactionObject) transaction; + txObject.setSessionHolder(new SessionHolder(session)); + txObject.getSessionHolder().setSynchronizedWithTransaction(true); + + // Register transaction timeout. + int timeout = determineTimeout(definition); + if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) { + txObject.getSessionHolder().setTimeoutInSeconds(timeout); + } + + // Enforce early database transaction for TopLink read-write transaction, + // unless we are explicitly told to use lazy transactions. + if (!definition.isReadOnly() && !isLazyDatabaseTransaction()) { + session.getActiveUnitOfWork().beginEarlyTransaction(); + } + + // Register the TopLink Session's JDBC Connection for the DataSource, if set. + if (getDataSource() != null) { + Session mostSpecificSession = (!definition.isReadOnly() ? session.getActiveUnitOfWork() : session); + Connection con = getJdbcConnection(mostSpecificSession); + if (con != null) { + ConnectionHolder conHolder = new ConnectionHolder(con); + if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) { + conHolder.setTimeoutInSeconds(timeout); + } + if (logger.isDebugEnabled()) { + logger.debug("Exposing TopLink transaction as JDBC transaction [" + con + "]"); + } + TransactionSynchronizationManager.bindResource(getDataSource(), conHolder); + txObject.setConnectionHolder(conHolder); + } + else { + if (logger.isDebugEnabled()) { + logger.debug("Not exposing TopLink transaction [" + session + + "] as JDBC transaction because no JDBC Connection could be retrieved from it"); + } + } + } + + // Bind the session holder to the thread. + TransactionSynchronizationManager.bindResource(getSessionFactory(), txObject.getSessionHolder()); + } + + catch (Exception ex) { + SessionFactoryUtils.releaseSession(session, getSessionFactory()); + throw new CannotCreateTransactionException("Could not open TopLink Session for transaction", ex); + } + } + + /** + * Extract the underlying JDBC Connection from the given TopLink Session. + *

Default implementation casts to oracle.toplink.publicinterface.Session + * and fetches the Connection from the DatabaseAccessor exposed there. + * @param session the current TopLink Session + * @return the underlying JDBC Connection, or null if none found + * @see oracle.toplink.publicinterface.Session#getAccessor() + * @see oracle.toplink.internal.databaseaccess.DatabaseAccessor#getConnection() + */ + protected Connection getJdbcConnection(Session session) { + if (!(session instanceof oracle.toplink.publicinterface.Session)) { + if (logger.isDebugEnabled()) { + logger.debug("TopLink Session [" + session + + "] does not derive from [oracle.toplink.publicinterface.Session]"); + } + return null; + } + Accessor accessor = ((oracle.toplink.publicinterface.Session) session).getAccessor(); + if (!(accessor instanceof DatabaseAccessor)) { + if (logger.isDebugEnabled()) { + logger.debug("TopLink Accessor [" + accessor + + "] does not derive from [oracle.toplink.internal.databaseaccess.DatabaseAccessor]"); + } + return null; + } + return ((DatabaseAccessor) accessor).getConnection(); + } + + protected Object doSuspend(Object transaction) { + TopLinkTransactionObject txObject = (TopLinkTransactionObject) transaction; + txObject.setSessionHolder(null); + return TransactionSynchronizationManager.unbindResource(getSessionFactory()); + } + + protected void doResume(Object transaction, Object suspendedResources) { + SessionHolder sessionHolder = (SessionHolder) 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(), sessionHolder); + } + + protected void doCommit(DefaultTransactionStatus status) { + TopLinkTransactionObject txObject = (TopLinkTransactionObject) status.getTransaction(); + if (status.isDebug()) { + logger.debug("Committing TopLink transaction on session [" + + txObject.getSessionHolder().getSession() + "]"); + } + try { + if (!status.isReadOnly()) { + txObject.getSessionHolder().getSession().getActiveUnitOfWork().commit(); + } + txObject.getSessionHolder().clear(); + } + catch (TopLinkException ex) { + throw convertTopLinkAccessException(ex); + } + } + + protected void doRollback(DefaultTransactionStatus status) { + TopLinkTransactionObject txObject = (TopLinkTransactionObject) status.getTransaction(); + if (status.isDebug()) { + logger.debug("Not committing TopLink transaction on session [" + + txObject.getSessionHolder().getSession() + "]"); + } + txObject.getSessionHolder().clear(); + } + + protected void doSetRollbackOnly(DefaultTransactionStatus status) { + TopLinkTransactionObject txObject = (TopLinkTransactionObject) status.getTransaction(); + if (status.isDebug()) { + logger.debug("Setting TopLink transaction on session [" + + txObject.getSessionHolder().getSession() + "] rollback-only"); + } + txObject.getSessionHolder().setRollbackOnly(); + } + + protected void doCleanupAfterCompletion(Object transaction) { + TopLinkTransactionObject txObject = (TopLinkTransactionObject) transaction; + + // Remove the session holder from the thread. + TransactionSynchronizationManager.unbindResource(getSessionFactory()); + + // Remove the JDBC connection holder from the thread, if exposed. + if (txObject.hasConnectionHolder()) { + TransactionSynchronizationManager.unbindResource(getDataSource()); + } + + Session session = txObject.getSessionHolder().getSession(); + if (logger.isDebugEnabled()) { + logger.debug("Releasing TopLink Session [" + session + "] after transaction"); + } + try { + session.release(); + } + catch (Throwable ex) { + // just log it, to keep a transaction-related exception + logger.debug("Could not release TopLink Session after transaction", ex); + } + } + + /** + * Convert the given TopLinkException to an appropriate exception from the + * org.springframework.dao hierarchy. + *

Will automatically apply a specified SQLExceptionTranslator to a + * TopLink DatabaseException, else rely on TopLink's default translation. + * @param ex TopLinkException that occured + * @return a corresponding DataAccessException + * @see SessionFactoryUtils#convertTopLinkAccessException + * @see #setJdbcExceptionTranslator + */ + protected DataAccessException convertTopLinkAccessException(TopLinkException ex) { + if (getJdbcExceptionTranslator() != null && ex instanceof DatabaseException) { + Throwable internalEx = ex.getInternalException(); + // Should always be a SQLException inside a DatabaseException. + if (internalEx instanceof SQLException) { + return getJdbcExceptionTranslator().translate( + "TopLink commit: " + ex.getMessage(), null, (SQLException) internalEx); + } + } + return SessionFactoryUtils.convertTopLinkAccessException(ex); + } + + + /** + * TopLink transaction object, representing a SessionHolder. + * Used as transaction object by TopLinkTransactionManager. + */ + private static class TopLinkTransactionObject extends JdbcTransactionObjectSupport { + + private SessionHolder sessionHolder; + + public void setSessionHolder(SessionHolder sessionHolder) { + this.sessionHolder = sessionHolder; + } + + public SessionHolder getSessionHolder() { + return this.sessionHolder; + } + + public boolean isRollbackOnly() { + return getSessionHolder().isRollbackOnly(); + } + } + +} Index: 3rdParty_sources/spring/org/springframework/orm/toplink/UnitOfWorkCallback.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/toplink/UnitOfWorkCallback.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/orm/toplink/UnitOfWorkCallback.java 17 Aug 2012 15:16:11 -0000 1.1 @@ -0,0 +1,77 @@ +/* + * 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.toplink; + +import oracle.toplink.exceptions.TopLinkException; +import oracle.toplink.sessions.Session; +import oracle.toplink.sessions.UnitOfWork; + +/** + * Convenient abstract implementation of the TopLinkCallback interface, + * exposing a UnitOfWork to perform write operations on. + * + *

The exposed UnitOfWork will either be be the active UnitOfWork of + * the current transaction, if any, or a temporarily acquired UnitOfWork + * that will be committed at the end of the operation. + * + * @author Juergen Hoeller + * @since 1.2 + * @see #doInUnitOfWork(oracle.toplink.sessions.UnitOfWork) + * @see oracle.toplink.sessions.Session#getActiveUnitOfWork() + */ +public abstract class UnitOfWorkCallback implements TopLinkCallback { + + /** + * Determines the UnitOfWork to work on (either the active UnitOfWork or a + * temporarily acquired UnitOfWork) and delegates to doInUnitOfWork. + * @see #doInUnitOfWork(oracle.toplink.sessions.UnitOfWork) + */ + public final Object doInTopLink(Session session) throws TopLinkException { + // Fetch active UnitOfWork or acquire temporary UnitOfWork. + UnitOfWork unitOfWork = session.getActiveUnitOfWork(); + boolean newUnitOfWork = false; + if (unitOfWork == null) { + unitOfWork = session.acquireUnitOfWork(); + newUnitOfWork = true; + } + + // Perform callback operation, committing the UnitOfWork unless + // it is the active UnitOfWork of an externally managed transaction. + try { + Object result = doInUnitOfWork(unitOfWork); + if (newUnitOfWork) { + unitOfWork.commit(); + } + return result; + } + finally { + if (newUnitOfWork) { + unitOfWork.release(); + } + } + } + + /** + * Called with a UnitOfWork to work on, either the active UnitOfWork or a + * temporarily acquired UnitOfWork (as determined by the transaction status). + * @param unitOfWork the TopLink UnitOfWork to perform write operations on + * @return a result object, or null if none + * @throws TopLinkException in case of TopLink errors + */ + protected abstract Object doInUnitOfWork(UnitOfWork unitOfWork) throws TopLinkException; + +} Index: 3rdParty_sources/spring/org/springframework/orm/toplink/package.html =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/toplink/package.html,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/orm/toplink/package.html 17 Aug 2012 15:16:11 -0000 1.1 @@ -0,0 +1,13 @@ + + + +Package providing integration of +Oracle TopLink +with Spring concepts. + +

Contains SessionFactory helper classes, a template plus callback +for TopLink access, and an implementation of Spring's transaction SPI +for local TopLink transactions. + + + Index: 3rdParty_sources/spring/org/springframework/orm/toplink/support/CommonsLoggingSessionLog.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/toplink/support/CommonsLoggingSessionLog.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/orm/toplink/support/CommonsLoggingSessionLog.java 17 Aug 2012 15:16:17 -0000 1.1 @@ -0,0 +1,217 @@ +/* + * 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.toplink.support; + +import java.lang.reflect.Method; + +import oracle.toplink.internal.databaseaccess.Accessor; +import oracle.toplink.logging.AbstractSessionLog; +import oracle.toplink.logging.SessionLogEntry; +import oracle.toplink.publicinterface.Session; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import org.springframework.util.ReflectionUtils; + +/** + * TopLink 10.1.3+ SessionLog implementation that logs through Commons Logging. + * + *

The namespace used is "oracle.toplink.xxx", with the latter part being + * the TopLink log category ("sql"/"transaction"/etc). In case of no category + * given, "session" will be used as default. This allows for fine-grained + * filtering of log messages, for example through Log4J configuration. + * + *

Maps TopLink's SEVERE level to CL ERROR, TopLink's WARNING to CL WARN, + * TopLink's INFO to CL INFO, TopLink's CONFIG/FINE/FINER to CL DEBUG, + * and TopLink's FINEST to CL TRACE. This results in common CL log behavior: + * INFO logging only at startup; operation logging at DEBUG level. Debug logging + * can be further filtered according to categories: for example, activate Log4J + * DEBUG logging for category "oracle.toplink.sql" to see the generated SQL. + * + *

Note: This implementation will only work on TopLink 10.1.3 or higher, + * as it is built against TopLink's new SessionLog facilities in the + * oracle.toplink.logging package, supporting log categories. + * + * @author Juergen Hoeller + * @since 1.2 + * @see CommonsLoggingSessionLog904 + * @see oracle.toplink.logging.JavaLog + * @see org.springframework.orm.toplink.LocalSessionFactoryBean#setSessionLog + */ +public class CommonsLoggingSessionLog extends AbstractSessionLog { + + public static final String NAMESPACE_PREFIX = "oracle.toplink."; + + public static final String DEFAULT_NAMESPACE = "session"; + + public static final String DEFAULT_SEPARATOR = "--"; + + + private static Method getSessionMethod; + + private static Method getExceptionMethod; + + static { + try { + getSessionMethod = SessionLogEntry.class.getMethod("getSession", new Class[0]); + } + catch (NoSuchMethodException ex) { + throw new IllegalStateException("Could not find method SessionLogEntry.getSession()"); + } + try { + getExceptionMethod = SessionLogEntry.class.getMethod("getException", new Class[0]); + } + catch (NoSuchMethodException ex) { + throw new IllegalStateException("Could not find method SessionLogEntry.getException()"); + } + } + + + private String separator = DEFAULT_SEPARATOR; + + + /** + * Specify the separator between TopLink's supplemental details + * (session, connection) and the log message itself. Default is "--". + */ + public void setSeparator(String separator) { + this.separator = separator; + } + + /** + * Return the separator between TopLink's supplemental details + * (session, connection) and the log message itself. Default is "--". + */ + public String getSeparator() { + return this.separator; + } + + + public void log(SessionLogEntry entry) { + Log logger = LogFactory.getLog(getCategory(entry)); + switch (entry.getLevel()) { + case SEVERE: + if (logger.isErrorEnabled()) { + if (entry.hasException()) { + logger.error(getMessageString(entry), getException(entry)); + } + else { + logger.error(getMessageString(entry)); + } + } + break; + case WARNING: + if (logger.isWarnEnabled()) { + if (entry.hasException()) { + logger.warn(getMessageString(entry), getException(entry)); + } + else { + logger.warn(getMessageString(entry)); + } + } + break; + case INFO: + if (logger.isInfoEnabled()) { + if (entry.hasException()) { + logger.info(getMessageString(entry), getException(entry)); + } + else { + logger.info(getMessageString(entry)); + } + } + break; + case CONFIG: + case FINE: + case FINER: + if (logger.isDebugEnabled()) { + if (entry.hasException()) { + logger.debug(getMessageString(entry), getException(entry)); + } + else { + logger.debug(getMessageString(entry)); + } + } + break; + case FINEST: + if (logger.isTraceEnabled()) { + if (entry.hasException()) { + logger.trace(getMessageString(entry), getException(entry)); + } + else { + logger.trace(getMessageString(entry)); + } + } + break; + } + } + + /** + * Determine the log category for the given log entry. + *

If the entry carries a name space value, it will be appended + * to the "oracle.toplink." prefix; else, "oracle.toplink.session" + * will be used. + */ + protected String getCategory(SessionLogEntry entry) { + String namespace = entry.getNameSpace(); + return NAMESPACE_PREFIX + (namespace != null ? namespace : DEFAULT_NAMESPACE); + } + + /** + * Build the message String for the given log entry, including the + * supplemental details (session, connection) and the formatted message. + * @see #getSessionString(oracle.toplink.sessions.Session) + * @see #getConnectionString(oracle.toplink.internal.databaseaccess.Accessor) + * @see #formatMessage(oracle.toplink.logging.SessionLogEntry) + * @see #getSeparator() + */ + protected String getMessageString(SessionLogEntry entry) { + StringBuffer buf = new StringBuffer(); + Session session = getSession(entry); + if (session != null) { + buf.append(getSessionString(session)); + buf.append(getSeparator()); + } + Accessor connection = entry.getConnection(); + if (connection != null) { + buf.append(getConnectionString(connection)); + buf.append(getSeparator()); + } + buf.append(formatMessage(entry)); + return buf.toString(); + } + + /** + * Extract the exception from the given log entry. + *

The default implementation calls SessionLogEntry.getSession + * via reflection: The return type varies between TopLink 10.1.3 and 11 + * (Session vs AbstractSession, respectively). + */ + protected Session getSession(SessionLogEntry entry) { + return (Session) ReflectionUtils.invokeMethod(getSessionMethod, entry); + } + + /** + * Extract the exception from the given log entry. + *

The default implementation calls SessionLogEntry.getException + * via reflection: The return type varies between TopLink 9.0.4 and 10.1.3 + * (Exception vs Throwable, respectively). + */ + protected Throwable getException(SessionLogEntry entry) { + return (Throwable) ReflectionUtils.invokeMethod(getExceptionMethod, entry); + } + +} Index: 3rdParty_sources/spring/org/springframework/orm/toplink/support/CommonsLoggingSessionLog904.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/toplink/support/CommonsLoggingSessionLog904.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/orm/toplink/support/CommonsLoggingSessionLog904.java 17 Aug 2012 15:16:17 -0000 1.1 @@ -0,0 +1,147 @@ +/* + * 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.toplink.support; + +import oracle.toplink.sessions.DefaultSessionLog; +import oracle.toplink.sessions.Session; +import oracle.toplink.sessions.SessionLogEntry; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * TopLink 9.0.4 SessionLog implementation that logs through Commons Logging. + * + *

The namespace used is "oracle.toplink.session". Fine-grained filtering + * of log messages, for example through Log4J configuration, is not + * available on TopLink 9.0.4: Consider upgrading to TopLink 10.1.3 and + * using the CommonsLoggingSessionLog class instead. + * + *

TopLink log entries with exceptions are logged at CL WARN level, + * TopLink debug log entries at CL TRACE level, and any other log entry + * at CL DEBUG level. Finer-grained mapping to log levels is unfortunately + * not possible on TopLink 9.0.4. + * + *

Note: This implementation will only actually work on TopLink 9.0.4, + * as it is built against TopLink's old SessionLog facilities in the + * oracle.toplink.sessions package, which are effectively + * obsolete (deprecated and bypassed) as of TopLink 10.1.3. + * + * @author Juergen Hoeller + * @since 1.2 + * @see CommonsLoggingSessionLog + * @see oracle.toplink.sessions.DefaultSessionLog + * @see org.springframework.orm.toplink.LocalSessionFactoryBean#setSessionLog + */ +public class CommonsLoggingSessionLog904 extends DefaultSessionLog { + + public static final String NAMESPACE = "oracle.toplink.session"; + + public static final String DEFAULT_SEPARATOR = "--"; + + + private final Log logger = LogFactory.getLog(NAMESPACE); + + private String separator = DEFAULT_SEPARATOR; + + + /** + * Specify the separator between TopLink's supplemental details + * (session, connection) and the log message itself. Default is "--". + */ + public void setSeparator(String separator) { + this.separator = separator; + } + + /** + * Return the separator between TopLink's supplemental details + * (session, connection) and the log message itself. Default is "--". + */ + public String getSeparator() { + return separator; + } + + + public void log(SessionLogEntry entry) { + if (entry.hasException()) { + if (shouldLogExceptions() && logger.isWarnEnabled()) { + this.logger.warn(getMessageString(entry), entry.getException()); + } + } + else if (entry.isDebug()) { + if (shouldLogDebug() && logger.isTraceEnabled()) { + this.logger.trace(getMessageString(entry)); + } + } + else { + if (logger.isDebugEnabled()) { + this.logger.debug(getMessageString(entry)); + } + } + } + + /** + * Build the message String for the given log entry, including the + * supplemental details (session, connection) and the message text. + * @see #getSeparator() + */ + protected String getMessageString(SessionLogEntry entry) { + StringBuffer buf = new StringBuffer(); + if (shouldPrintSession()) { + buf.append(getSessionName(entry.getSession())); + buf.append("("); + buf.append(String.valueOf(System.identityHashCode(entry.getSession()))); + buf.append(")"); + buf.append(getSeparator()); + } + if (shouldPrintConnection() && entry.getConnection() != null) { + buf.append("Connection"); + buf.append("("); + buf.append(String.valueOf(System.identityHashCode(entry.getConnection()))); + buf.append(")"); + buf.append(getSeparator()); + } + buf.append(entry.getMessage()); + return buf.toString(); + } + + /** + * Return the name to be used for the given Session + * ("UnitOfWork"/"ServerSession"/"ClientSession"/etc). + */ + protected String getSessionName(Session session) { + if (session.isUnitOfWork()) { + return "UnitOfWork"; + } + if (session.isServerSession()) { + return "ServerSession"; + } + if (session.isClientSession()) { + return "ClientSession"; + } + if (session.isSessionBroker()) { + return "SessionBroker"; + } + if (session.isRemoteSession()) { + return "RemoteSession"; + } + if (session.isDatabaseSession()) { + return "DatabaseSession"; + } + return "Session"; + } + +} Index: 3rdParty_sources/spring/org/springframework/orm/toplink/support/TopLinkDaoSupport.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/toplink/support/TopLinkDaoSupport.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/orm/toplink/support/TopLinkDaoSupport.java 17 Aug 2012 15:16:17 -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.orm.toplink.support; + +import oracle.toplink.exceptions.TopLinkException; +import oracle.toplink.sessions.Session; + +import org.springframework.dao.DataAccessException; +import org.springframework.dao.DataAccessResourceFailureException; +import org.springframework.dao.support.DaoSupport; +import org.springframework.orm.toplink.SessionFactory; +import org.springframework.orm.toplink.SessionFactoryUtils; +import org.springframework.orm.toplink.TopLinkTemplate; + +/** + * Convenient super class for TopLink data access objects. + * + *

Requires a SessionFactory to be set, providing a TopLinkTemplate + * based on it to subclasses. Can alternatively be initialized directly with + * a TopLinkTemplate, to reuse the latter's settings such as the SessionFactory, + * exception translator, etc. + * + *

This base class is mainly intended for TopLinkTemplate usage + * but can also be used when working with SessionFactoryUtils directly, + * for example in combination with TopLinkInterceptor-managed Sessions. + * Convenience getSession and releaseSession + * methods are provided for that usage style. + * + * @author Juergen Hoeller + * @since 1.2 + * @see #setSessionFactory + * @see #setTopLinkTemplate + * @see #getSession + * @see #releaseSession + * @see org.springframework.orm.toplink.TopLinkTemplate + * @see org.springframework.orm.toplink.TopLinkInterceptor + */ +public abstract class TopLinkDaoSupport extends DaoSupport { + + private TopLinkTemplate topLinkTemplate; + + + /** + * Set the TopLink SessionFactory to be used by this DAO. + * Will automatically create a TopLinkTemplate for the given SessionFactory. + * @see #createTopLinkTemplate + * @see #setTopLinkTemplate + */ + public final void setSessionFactory(SessionFactory sessionFactory) { + if (this.topLinkTemplate == null || sessionFactory != this.topLinkTemplate.getSessionFactory()) { + this.topLinkTemplate = createTopLinkTemplate(sessionFactory); + } + } + + /** + * Create a TopLinkTemplate for the given SessionFactory. + * Only invoked if populating the DAO with a SessionFactory reference! + *

Can be overridden in subclasses to provide a TopLinkTemplate instance + * with different configuration, or a custom TopLinkTemplate subclass. + * @param sessionFactory the TopLink SessionFactory to create a TopLinkTemplate for + * @return the new TopLinkTemplate instance + * @see #setSessionFactory + */ + protected TopLinkTemplate createTopLinkTemplate(SessionFactory sessionFactory) { + return new TopLinkTemplate(sessionFactory); + } + + /** + * Return the TopLink SessionFactory used by this DAO. + */ + public final SessionFactory getSessionFactory() { + return (this.topLinkTemplate != null ? this.topLinkTemplate.getSessionFactory() : null); + } + + /** + * Set the TopLinkTemplate for this DAO explicitly, + * as an alternative to specifying a SessionFactory. + * @see #setSessionFactory + */ + public final void setTopLinkTemplate(TopLinkTemplate topLinkTemplate) { + this.topLinkTemplate = topLinkTemplate; + } + + /** + * Return the TopLinkTemplate for this DAO, + * pre-initialized with the SessionFactory or set explicitly. + */ + public final TopLinkTemplate getTopLinkTemplate() { + return topLinkTemplate; + } + + protected final void checkDaoConfig() { + if (this.topLinkTemplate == null) { + throw new IllegalArgumentException("sessionFactory or topLinkTemplate is required"); + } + } + + + /** + * Get a TopLink Session, either from the current transaction or a new one. + * The latter is only allowed if the "allowCreate" setting of this bean's + * TopLinkTemplate is true. + *

Note that this is not meant to be invoked from TopLinkTemplate code + * but rather just in plain TopLink code. Either rely on a thread-bound + * Session (via TopLinkInterceptor), or use it in combination with + * releaseSession. + *

In general, it is recommended to use TopLinkTemplate, either with + * the provided convenience operations or with a custom TopLinkCallback + * that provides you with a Session to work on. TopLinkTemplate will care + * for all resource management and for proper exception conversion. + * @return the TopLink Session + * @throws DataAccessResourceFailureException if the Session couldn't be created + * @throws IllegalStateException if no thread-bound Session found and allowCreate false + * @see TopLinkTemplate + * @see org.springframework.orm.toplink.SessionFactoryUtils#getSession(SessionFactory, boolean) + * @see org.springframework.orm.toplink.TopLinkInterceptor + * @see org.springframework.orm.toplink.TopLinkTemplate + * @see org.springframework.orm.toplink.TopLinkCallback + */ + protected final Session getSession() + throws DataAccessResourceFailureException, IllegalStateException { + + return getSession(this.topLinkTemplate.isAllowCreate()); + } + + /** + * Get a TopLink 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 TopLinkTemplate code + * but rather just in plain TopLink code. Either rely on a thread-bound + * Session (via TopLinkInterceptor), or use it in combination with + * releaseSession. + *

In general, it is recommended to use TopLinkTemplate, either with + * the provided convenience operations or with a custom TopLinkCallback + * that provides you with a Session to work on. TopLinkTemplate will care + * for all resource management and for proper exception conversion. + * @param allowCreate if a new Session should be created if no thread-bound found + * @return the TopLink 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.toplink.SessionFactoryUtils#getSession(SessionFactory, boolean) + * @see org.springframework.orm.toplink.TopLinkInterceptor + * @see org.springframework.orm.toplink.TopLinkTemplate + * @see org.springframework.orm.toplink.TopLinkCallback + */ + protected final Session getSession(boolean allowCreate) + throws DataAccessResourceFailureException, IllegalStateException { + + return SessionFactoryUtils.getSession(this.getSessionFactory(), allowCreate); + } + + /** + * Convert the given TopLinkException to an appropriate exception from the + * org.springframework.dao hierarchy. Will automatically detect + * wrapped SQLExceptions and convert them accordingly. + *

Delegates to the convertTopLinkAccessException method of this + * DAO's TopLinkTemplate. + * @param ex TopLinkException that occured + * @return the corresponding DataAccessException instance + * @see #setTopLinkTemplate + * @see org.springframework.orm.toplink.TopLinkTemplate#convertTopLinkAccessException + */ + protected final DataAccessException convertTopLinkAccessException(TopLinkException ex) { + return this.topLinkTemplate.convertTopLinkAccessException(ex); + } + + /** + * Close the given TopLink Session, created via this DAO's SessionFactory, + * if it isn't bound to the thread. + * @param session the TopLink Session to close + * @see org.springframework.orm.toplink.SessionFactoryUtils#releaseSession + */ + protected final void releaseSession(Session session) { + SessionFactoryUtils.releaseSession(session, getSessionFactory()); + } + +} Index: 3rdParty_sources/spring/org/springframework/orm/toplink/support/TransactionAwareSessionAdapter.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/toplink/support/TransactionAwareSessionAdapter.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/orm/toplink/support/TransactionAwareSessionAdapter.java 17 Aug 2012 15:16:17 -0000 1.1 @@ -0,0 +1,89 @@ +/* + * 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.toplink.support; + +import oracle.toplink.sessions.Session; + +import org.springframework.beans.factory.FactoryBean; +import org.springframework.orm.toplink.SessionFactory; + +/** + * This adapter FactoryBean takes a TopLink SessionFactory and exposes a + * corresponding transaction-aware TopLink Session as bean reference. + * + *

This adapter bean will usually be defined in front of a Spring + * LocalSessionFactoryBean, to allow for passing Session references to DAOs + * that expect to work on a raw TopLink Session. Your DAOs can then, + * for example, access the currently active Session and UnitOfWork via + * Session.getActiveSession() and + * Session.getActiveUnitOfWork(), respectively. + * + *

The main advantage of this proxy is that it allows DAOs to work with a + * plain TopLink Session reference, while still participating in Spring's + * (or a J2EE server's) resource and transaction management. DAOs will only + * rely on the TopLink API in such a scenario, without any Spring dependencies. + * + *

It is usually preferable to write your TopLink-based DAOs with Spring's + * TopLinkTemplate, offering benefits such as consistent data access exceptions + * instead of TopLinkExceptions at the DAO layer. However, Spring's resource + * and transaction management (and Dependency Injection) will work for DAOs + * written against the plain TopLink API too. + * + *

Of course, you can still access the target TopLink SessionFactory + * even when your DAOs go through this adapter, by defining a bean reference + * that points directly at your target SessionFactory bean. + * + *

Note that the actual creation of a transaction-aware TopLink Session + * is available on the TopLink SessionFactory itself. This adapter FactoryBean + * is just a convenient way to expose such a Session in a declarative fashion. + * + * @author Juergen Hoeller + * @since 1.2 + * @see org.springframework.orm.toplink.LocalSessionFactoryBean + * @see org.springframework.orm.toplink.SessionFactory#createTransactionAwareSession() + * @see oracle.toplink.sessions.Session#getActiveSession() + * @see oracle.toplink.sessions.Session#getActiveUnitOfWork() + */ +public class TransactionAwareSessionAdapter implements FactoryBean { + + private Session session; + + + /** + * Set the SessionFactory that this adapter is supposed to expose a + * transaction-aware TopLink Session for. This should be the raw + * SessionFactory, as accessed by TopLinkTransactionManager. + * @see org.springframework.orm.toplink.TopLinkTransactionManager + */ + public void setSessionFactory(SessionFactory sessionFactory) { + this.session = sessionFactory.createTransactionAwareSession(); + } + + + public Object getObject() { + return this.session; + } + + public Class getObjectType() { + return Session.class; + } + + public boolean isSingleton() { + return true; + } + +} Index: 3rdParty_sources/spring/org/springframework/orm/toplink/support/package.html =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/toplink/support/package.html,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/orm/toplink/support/package.html 17 Aug 2012 15:16:17 -0000 1.1 @@ -0,0 +1,8 @@ + + + +Classes supporting the org.springframework.orm.toplink package. +Contains a DAO base class for TopLinkTemplate usage. + + + Index: 3rdParty_sources/spring/org/springframework/remoting/RemoteAccessException.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/remoting/RemoteAccessException.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/remoting/RemoteAccessException.java 17 Aug 2012 15:16:16 -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.remoting; + +import org.springframework.core.NestedRuntimeException; + +/** + * Generic remote access exception. A service proxy for any remoting + * protocol should throw this exception or subclasses of it, in order + * to transparently expose a plain Java business interface. + * + *

When using conforming proxies, switching the actual remoting protocol + * e.g. from Hessian to Burlap does not affect client code. Clients work + * with a plain natural Java business interface that the service exposes. + * A client object simply receives an implementation for the interface that + * it needs via a bean reference, like it does for a local bean as well. + * + *

A client may catch RemoteAccessException if it wants to, but as + * remote access errors are typically unrecoverable, it will probably let + * such exceptions propagate to a higher level that handles them generically. + * In this case, the client code doesn't show any signs of being involved in + * remote access, as there aren't any remoting-specific dependencies. + * + *

Even when switching from a remote service proxy to a local implementation + * of the same interface, this amounts to just a matter of configuration. Obviously, + * the client code should be somewhat aware that it might be working + * against a remote service, for example in terms of repeated method calls that + * cause unnecessary roundtrips etc. However, it doesn't have to be aware whether + * it is actually working against a remote service or a local implementation, + * or with which remoting protocol it is working under the hood. + * + * @author Juergen Hoeller + * @since 14.05.2003 + */ +public class RemoteAccessException extends NestedRuntimeException { + + /** Use serialVersionUID from Spring 1.2 for interoperability */ + private static final long serialVersionUID = -4906825139312227864L; + + + /** + * Constructor for RemoteAccessException. + * @param msg the detail message + */ + public RemoteAccessException(String msg) { + super(msg); + } + + /** + * Constructor for RemoteAccessException. + * @param msg the detail message + * @param cause the root cause (usually from using an underlying + * remoting API such as RMI) + */ + public RemoteAccessException(String msg, Throwable cause) { + super(msg, cause); + } + +} Index: 3rdParty_sources/spring/org/springframework/remoting/RemoteConnectFailureException.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/remoting/RemoteConnectFailureException.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/remoting/RemoteConnectFailureException.java 17 Aug 2012 15:16:16 -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.remoting; + +/** + * RemoteAccessException subclass to be thrown when no connection + * could be established with a remote service. + * + * @author Juergen Hoeller + * @since 1.1 + */ +public class RemoteConnectFailureException extends RemoteAccessException { + + /** + * Constructor for RemoteConnectFailureException. + * @param msg the detail message + * @param cause the root cause from the remoting API in use + */ + public RemoteConnectFailureException(String msg, Throwable cause) { + super(msg, cause); + } + +} Index: 3rdParty_sources/spring/org/springframework/remoting/RemoteInvocationFailureException.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/remoting/RemoteInvocationFailureException.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/remoting/RemoteInvocationFailureException.java 17 Aug 2012 15:16:16 -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.remoting; + +/** + * RemoteAccessException subclass to be thrown when the execution + * of the target method failed on the server side, for example + * when a method was not found on the target object. + * + * @author Juergen Hoeller + * @since 2.5 + * @see RemoteProxyFailureException + */ +public class RemoteInvocationFailureException extends RemoteAccessException { + + /** + * Constructor for RemoteInvocationFailureException. + * @param msg the detail message + * @param cause the root cause from the remoting API in use + */ + public RemoteInvocationFailureException(String msg, Throwable cause) { + super(msg, cause); + } + +} Index: 3rdParty_sources/spring/org/springframework/remoting/RemoteLookupFailureException.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/remoting/RemoteLookupFailureException.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/remoting/RemoteLookupFailureException.java 17 Aug 2012 15:16:16 -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.remoting; + +/** + * RemoteAccessException subclass to be thrown in case of a lookup failure, + * typically if the lookup happens on demand for each method invocation. + * + * @author Juergen Hoeller + * @since 1.1 + */ +public class RemoteLookupFailureException extends RemoteAccessException { + + /** + * Constructor for RemoteLookupFailureException. + * @param msg the detail message + */ + public RemoteLookupFailureException(String msg) { + super(msg); + } + + /** + * Constructor for RemoteLookupFailureException. + * @param msg message + * @param cause the root cause from the remoting API in use + */ + public RemoteLookupFailureException(String msg, Throwable cause) { + super(msg, cause); + } + +} Index: 3rdParty_sources/spring/org/springframework/remoting/RemoteProxyFailureException.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/remoting/RemoteProxyFailureException.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/remoting/RemoteProxyFailureException.java 17 Aug 2012 15:16:16 -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.remoting; + +/** + * RemoteAccessException subclass to be thrown in case of a failure + * within the client-side proxy for a remote service, for example + * when a method was not found on the underlying RMI stub. + * + * @author Juergen Hoeller + * @since 1.2.8 + * @see RemoteInvocationFailureException + */ +public class RemoteProxyFailureException extends RemoteAccessException { + + /** + * Constructor for RemoteProxyFailureException. + * @param msg the detail message + * @param cause the root cause from the remoting API in use + */ + public RemoteProxyFailureException(String msg, Throwable cause) { + super(msg, cause); + } + +} Index: 3rdParty_sources/spring/org/springframework/remoting/package.html =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/remoting/package.html,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/remoting/package.html 17 Aug 2012 15:16:16 -0000 1.1 @@ -0,0 +1,8 @@ + + + +Exception hierarchy for Spring's remoting infrastructure, +independent of any specific remote method invocation system. + + + Index: 3rdParty_sources/spring/org/springframework/remoting/caucho/BurlapClientInterceptor.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/remoting/caucho/BurlapClientInterceptor.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/remoting/caucho/BurlapClientInterceptor.java 17 Aug 2012 15:16:13 -0000 1.1 @@ -0,0 +1,187 @@ +/* + * 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.remoting.caucho; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.UndeclaredThrowableException; +import java.net.ConnectException; +import java.net.MalformedURLException; + +import com.caucho.burlap.client.BurlapProxyFactory; +import com.caucho.burlap.client.BurlapRuntimeException; +import org.aopalliance.intercept.MethodInterceptor; +import org.aopalliance.intercept.MethodInvocation; + +import org.springframework.remoting.RemoteAccessException; +import org.springframework.remoting.RemoteConnectFailureException; +import org.springframework.remoting.RemoteLookupFailureException; +import org.springframework.remoting.RemoteProxyFailureException; +import org.springframework.remoting.support.UrlBasedRemoteAccessor; +import org.springframework.util.Assert; + +/** + * {@link org.aopalliance.intercept.MethodInterceptor} for accessing a Burlap service. + * Supports authentication via username and password. + * The service URL must be an HTTP URL exposing a Burlap service. + * + *

Burlap is a slim, XML-based RPC protocol. + * For information on Burlap, see the + * Burlap website + * + *

Note: There is no requirement for services accessed with this proxy factory + * to have been exported using Spring's {@link BurlapServiceExporter}, as there is + * no special handling involved. As a consequence, you can also access services that + * have been exported using Caucho's {@link com.caucho.burlap.server.BurlapServlet}. + * + * @author Juergen Hoeller + * @since 29.09.2003 + * @see #setServiceInterface + * @see #setServiceUrl + * @see #setUsername + * @see #setPassword + * @see BurlapServiceExporter + * @see BurlapProxyFactoryBean + * @see com.caucho.burlap.client.BurlapProxyFactory + * @see com.caucho.burlap.server.BurlapServlet + */ +public class BurlapClientInterceptor extends UrlBasedRemoteAccessor implements MethodInterceptor { + + private BurlapProxyFactory proxyFactory = new BurlapProxyFactory(); + + private Object burlapProxy; + + + /** + * Set the BurlapProxyFactory instance to use. + * If not specified, a default BurlapProxyFactory will be created. + *

Allows to use an externally configured factory instance, + * in particular a custom BurlapProxyFactory subclass. + */ + public void setProxyFactory(BurlapProxyFactory proxyFactory) { + this.proxyFactory = (proxyFactory != null ? proxyFactory : new BurlapProxyFactory()); + } + + /** + * Set the username that this factory should use to access the remote service. + * Default is none. + *

The username will be sent by Burlap via HTTP Basic Authentication. + * @see com.caucho.burlap.client.BurlapProxyFactory#setUser + */ + public void setUsername(String username) { + this.proxyFactory.setUser(username); + } + + /** + * Set the password that this factory should use to access the remote service. + * Default is none. + *

The password will be sent by Burlap via HTTP Basic Authentication. + * @see com.caucho.burlap.client.BurlapProxyFactory#setPassword + */ + public void setPassword(String password) { + this.proxyFactory.setPassword(password); + } + + /** + * Set whether overloaded methods should be enabled for remote invocations. + * Default is "false". + * @see com.caucho.burlap.client.BurlapProxyFactory#setOverloadEnabled + */ + public void setOverloadEnabled(boolean overloadEnabled) { + this.proxyFactory.setOverloadEnabled(overloadEnabled); + } + + + public void afterPropertiesSet() { + super.afterPropertiesSet(); + prepare(); + } + + /** + * Initialize the Burlap proxy for this interceptor. + * @throws RemoteLookupFailureException if the service URL is invalid + */ + public void prepare() throws RemoteLookupFailureException { + try { + this.burlapProxy = createBurlapProxy(this.proxyFactory); + } + catch (MalformedURLException ex) { + throw new RemoteLookupFailureException("Service URL [" + getServiceUrl() + "] is invalid", ex); + } + } + + /** + * Create the Burlap proxy that is wrapped by this interceptor. + * @param proxyFactory the proxy factory to use + * @return the Burlap proxy + * @throws MalformedURLException if thrown by the proxy factory + * @see com.caucho.burlap.client.BurlapProxyFactory#create + */ + protected Object createBurlapProxy(BurlapProxyFactory proxyFactory) throws MalformedURLException { + Assert.notNull(getServiceInterface(), "Property 'serviceInterface' is required"); + return proxyFactory.create(getServiceInterface(), getServiceUrl()); + } + + + public Object invoke(MethodInvocation invocation) throws Throwable { + if (this.burlapProxy == null) { + throw new IllegalStateException("BurlapClientInterceptor is not properly initialized - " + + "invoke 'prepare' before attempting any operations"); + } + + ClassLoader originalClassLoader = overrideThreadContextClassLoader(); + try { + return invocation.getMethod().invoke(this.burlapProxy, invocation.getArguments()); + } + catch (InvocationTargetException ex) { + if (ex.getTargetException() instanceof BurlapRuntimeException) { + BurlapRuntimeException bre = (BurlapRuntimeException) ex.getTargetException(); + Throwable rootCause = (bre.getRootCause() != null ? bre.getRootCause() : bre); + throw convertBurlapAccessException(rootCause); + } + else if (ex.getTargetException() instanceof UndeclaredThrowableException) { + UndeclaredThrowableException utex = (UndeclaredThrowableException) ex.getTargetException(); + throw convertBurlapAccessException(utex.getUndeclaredThrowable()); + } + throw ex.getTargetException(); + } + catch (Throwable ex) { + throw new RemoteProxyFailureException( + "Failed to invoke Burlap proxy for remote service [" + getServiceUrl() + "]", ex); + } + finally { + resetThreadContextClassLoader(originalClassLoader); + } + } + + /** + * Convert the given Burlap access exception to an appropriate + * Spring RemoteAccessException. + * @param ex the exception to convert + * @return the RemoteAccessException to throw + */ + protected RemoteAccessException convertBurlapAccessException(Throwable ex) { + if (ex instanceof ConnectException) { + return new RemoteConnectFailureException( + "Cannot connect to Burlap remote service at [" + getServiceUrl() + "]", ex); + } + else { + return new RemoteAccessException( + "Cannot access Burlap remote service at [" + getServiceUrl() + "]", ex); + } + } + +} Index: 3rdParty_sources/spring/org/springframework/remoting/caucho/BurlapExporter.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/remoting/caucho/BurlapExporter.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/remoting/caucho/BurlapExporter.java 17 Aug 2012 15:16:14 -0000 1.1 @@ -0,0 +1,110 @@ +/* + * 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.remoting.caucho; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.lang.reflect.Constructor; + +import com.caucho.burlap.io.BurlapInput; +import com.caucho.burlap.io.BurlapOutput; +import com.caucho.burlap.server.BurlapSkeleton; + +import org.springframework.beans.factory.BeanInitializationException; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.remoting.support.RemoteExporter; +import org.springframework.util.Assert; + +/** + * General stream-based protocol exporter for a Burlap endpoint. + * + *

Burlap is a slim, XML-based RPC protocol. + * For information on Burlap, see the + * Burlap website. + * + *

This exporter will work with both Burlap 2.x and 3.x (respectively + * Resin 2.x and 3.x), autodetecting the corresponding skeleton class. + * + * @author Juergen Hoeller + * @since 2.5.1 + * @see #invoke(java.io.InputStream, java.io.OutputStream) + * @see BurlapServiceExporter + * @see SimpleBurlapServiceExporter + */ +public class BurlapExporter extends RemoteExporter implements InitializingBean { + + private BurlapSkeleton skeleton; + + + public void afterPropertiesSet() { + prepare(); + } + + /** + * Initialize this service exporter. + */ + public void prepare() { + try { + try { + // Try Burlap 3.x (with service interface argument). + Constructor ctor = BurlapSkeleton.class.getConstructor(new Class[] {Object.class, Class.class}); + checkService(); + checkServiceInterface(); + this.skeleton = (BurlapSkeleton) + ctor.newInstance(new Object[] {getProxyForService(), getServiceInterface()}); + } + catch (NoSuchMethodException ex) { + // Fall back to Burlap 2.x (without service interface argument). + Constructor ctor = BurlapSkeleton.class.getConstructor(new Class[] {Object.class}); + this.skeleton = (BurlapSkeleton) ctor.newInstance(new Object[] {getProxyForService()}); + } + } + catch (Exception ex) { + throw new BeanInitializationException("Burlap skeleton initialization failed", ex); + } + } + + + /** + * Perform an invocation on the exported object. + * @param inputStream the request stream + * @param outputStream the response stream + * @throws Throwable if invocation failed + */ + public void invoke(InputStream inputStream, OutputStream outputStream) throws Throwable { + Assert.notNull(this.skeleton, "Burlap exporter has not been initialized"); + ClassLoader originalClassLoader = overrideThreadContextClassLoader(); + try { + this.skeleton.invoke(new BurlapInput(inputStream), new BurlapOutput(outputStream)); + } + finally { + try { + inputStream.close(); + } + catch (IOException ex) { + } + try { + outputStream.close(); + } + catch (IOException ex) { + } + resetThreadContextClassLoader(originalClassLoader); + } + } + +} Index: 3rdParty_sources/spring/org/springframework/remoting/caucho/BurlapProxyFactoryBean.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/remoting/caucho/BurlapProxyFactoryBean.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/remoting/caucho/BurlapProxyFactoryBean.java 17 Aug 2012 15:16:14 -0000 1.1 @@ -0,0 +1,66 @@ +/* + * 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.remoting.caucho; + +import org.springframework.aop.framework.ProxyFactory; +import org.springframework.beans.factory.FactoryBean; + +/** + * FactoryBean for Burlap proxies. Exposes the proxied service for + * use as a bean reference, using the specified service interface. + * + *

Burlap is a slim, XML-based RPC protocol. + * For information on Burlap, see the + * Burlap website + * + *

The service URL must be an HTTP URL exposing a Burlap service. + * For details, see the {@link BurlapClientInterceptor} javadoc. + * + * @author Juergen Hoeller + * @since 13.05.2003 + * @see #setServiceInterface + * @see #setServiceUrl + * @see BurlapClientInterceptor + * @see BurlapServiceExporter + * @see org.springframework.remoting.caucho.HessianProxyFactoryBean + * @see org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean + * @see org.springframework.remoting.rmi.RmiProxyFactoryBean + */ +public class BurlapProxyFactoryBean extends BurlapClientInterceptor implements FactoryBean { + + private Object serviceProxy; + + + public void afterPropertiesSet() { + super.afterPropertiesSet(); + this.serviceProxy = new ProxyFactory(getServiceInterface(), this).getProxy(getBeanClassLoader()); + } + + + public Object getObject() { + return this.serviceProxy; + } + + public Class getObjectType() { + return getServiceInterface(); + } + + public boolean isSingleton() { + return true; + } + +} Index: 3rdParty_sources/spring/org/springframework/remoting/caucho/BurlapServiceExporter.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/remoting/caucho/BurlapServiceExporter.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/remoting/caucho/BurlapServiceExporter.java 17 Aug 2012 15:16:13 -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.remoting.caucho; + +import java.io.IOException; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.springframework.web.HttpRequestHandler; +import org.springframework.web.HttpRequestMethodNotSupportedException; +import org.springframework.web.util.NestedServletException; + +/** + * Servlet-API-based HTTP request handler that exports the specified service bean + * as Burlap service endpoint, accessible via a Burlap proxy. + * + *

Note: Spring also provides an alternative version of this exporter, + * for Sun's JRE 1.6 HTTP server: {@link SimpleBurlapServiceExporter}. + * + *

Burlap is a slim, XML-based RPC protocol. + * For information on Burlap, see the + * Burlap website. + * + *

This exporter will work with both Burlap 2.x and 3.x (respectively + * Resin 2.x and 3.x), autodetecting the corresponding skeleton class. + * + *

Note: Burlap services exported with this class can be accessed by + * any Burlap client, as there isn't any special handling involved. + * + * @author Juergen Hoeller + * @since 13.05.2003 + * @see BurlapClientInterceptor + * @see BurlapProxyFactoryBean + * @see org.springframework.remoting.caucho.HessianServiceExporter + * @see org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter + * @see org.springframework.remoting.rmi.RmiServiceExporter + */ +public class BurlapServiceExporter extends BurlapExporter implements HttpRequestHandler { + + /** + * Processes the incoming Burlap request and creates a Burlap response. + */ + public void handleRequest(HttpServletRequest request, HttpServletResponse response) + throws ServletException, IOException { + + if (!"POST".equals(request.getMethod())) { + throw new HttpRequestMethodNotSupportedException(request.getMethod(), + new String[] {"POST"}, "BurlapServiceExporter only supports POST requests"); + } + + try { + invoke(request.getInputStream(), response.getOutputStream()); + } + catch (Throwable ex) { + throw new NestedServletException("Burlap skeleton invocation failed", ex); + } + } + +} Index: 3rdParty_sources/spring/org/springframework/remoting/caucho/Hessian1SkeletonInvoker.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/remoting/caucho/Hessian1SkeletonInvoker.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/remoting/caucho/Hessian1SkeletonInvoker.java 17 Aug 2012 15:16:13 -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.remoting.caucho; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.lang.reflect.Method; + +import com.caucho.hessian.io.HessianInput; +import com.caucho.hessian.io.HessianOutput; +import com.caucho.hessian.io.SerializerFactory; +import com.caucho.hessian.server.HessianSkeleton; + +import org.springframework.util.ClassUtils; + +/** + * Concrete HessianSkeletonInvoker for the Hessian 1 protocol + * (version 3.0.19 or lower). + * + * @author Juergen Hoeller + * @since 2.0 + */ +class Hessian1SkeletonInvoker extends HessianSkeletonInvoker { + + private static final Method invokeMethod; + + private static final boolean applySerializerFactoryToOutput; + + static { + invokeMethod = ClassUtils.getMethodIfAvailable( + HessianSkeleton.class, "invoke", new Class[] {HessianInput.class, HessianOutput.class}); + applySerializerFactoryToOutput = + ClassUtils.hasMethod(HessianOutput.class, "setSerializerFactory", new Class[] {SerializerFactory.class}); + } + + + public Hessian1SkeletonInvoker(HessianSkeleton skeleton, SerializerFactory serializerFactory) { + super(skeleton, serializerFactory); + if (invokeMethod == null) { + throw new IllegalStateException("Hessian 1 (version 3.0.19-) not present"); + } + } + + public void invoke(InputStream inputStream, OutputStream outputStream) throws Throwable { + HessianInput in = new HessianInput(inputStream); + HessianOutput out = new HessianOutput(outputStream); + if (this.serializerFactory != null) { + in.setSerializerFactory(this.serializerFactory); + if (applySerializerFactoryToOutput) { + out.setSerializerFactory(this.serializerFactory); + } + } + try { + invokeMethod.invoke(this.skeleton, new Object[] {in, out}); + } + finally { + try { + in.close(); + inputStream.close(); + } + catch (IOException ex) { + } + try { + out.close(); + outputStream.close(); + } + catch (IOException ex) { + } + } + + } + +} Index: 3rdParty_sources/spring/org/springframework/remoting/caucho/Hessian2SkeletonInvoker.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/remoting/caucho/Hessian2SkeletonInvoker.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/remoting/caucho/Hessian2SkeletonInvoker.java 17 Aug 2012 15:16:13 -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.remoting.caucho; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.PrintWriter; + +import com.caucho.hessian.io.AbstractHessianOutput; +import com.caucho.hessian.io.Hessian2Input; +import com.caucho.hessian.io.Hessian2Output; +import com.caucho.hessian.io.HessianDebugInputStream; +import com.caucho.hessian.io.HessianDebugOutputStream; +import com.caucho.hessian.io.HessianOutput; +import com.caucho.hessian.io.SerializerFactory; +import com.caucho.hessian.server.HessianSkeleton; +import org.apache.commons.logging.Log; + +import org.springframework.util.ClassUtils; +import org.springframework.util.CommonsLogWriter; + +/** + * Concrete HessianSkeletonInvoker for the Hessian 2 protocol + * (version 3.0.20 or higher). + * + * @author Juergen Hoeller + * @author Andy Piper + * @since 2.0 + */ +class Hessian2SkeletonInvoker extends HessianSkeletonInvoker { + + private static final boolean debugOutputStreamAvailable = ClassUtils.isPresent( + "com.caucho.hessian.io.HessianDebugOutputStream", Hessian2SkeletonInvoker.class.getClassLoader()); + + private final Log debugLogger; + + + public Hessian2SkeletonInvoker(HessianSkeleton skeleton, SerializerFactory serializerFactory, Log debugLog) { + super(skeleton, serializerFactory); + this.debugLogger = debugLog; + } + + public void invoke(final InputStream inputStream, final OutputStream outputStream) throws Throwable { + InputStream isToUse = inputStream; + OutputStream osToUse = outputStream; + + if (this.debugLogger != null && this.debugLogger.isDebugEnabled()) { + PrintWriter debugWriter = new PrintWriter(new CommonsLogWriter(this.debugLogger)); + isToUse = new HessianDebugInputStream(inputStream, debugWriter); + if (debugOutputStreamAvailable) { + osToUse = DebugStreamFactory.createDebugOutputStream(outputStream, debugWriter); + } + } + + Hessian2Input in = new Hessian2Input(isToUse); + if (this.serializerFactory != null) { + in.setSerializerFactory(this.serializerFactory); + } + + int code = in.read(); + if (code != 'c') { + throw new IOException("expected 'c' in hessian input at " + code); + } + + AbstractHessianOutput out = null; + int major = in.read(); + int minor = in.read(); + if (major >= 2) { + out = new Hessian2Output(osToUse); + } + else { + out = new HessianOutput(osToUse); + } + if (this.serializerFactory != null) { + out.setSerializerFactory(this.serializerFactory); + } + + try { + this.skeleton.invoke(in, out); + } + finally { + try { + in.close(); + isToUse.close(); + } + catch (IOException ex) { + } + try { + out.close(); + osToUse.close(); + } + catch (IOException ex) { + } + } + } + + + /** + * Inner class to avoid hard dependency on Hessian 3.1.3's HessianDebugOutputStream. + */ + private static class DebugStreamFactory { + + public static OutputStream createDebugOutputStream(OutputStream os, PrintWriter debug) { + return new HessianDebugOutputStream(os, debug); + } + } + +} Index: 3rdParty_sources/spring/org/springframework/remoting/caucho/HessianClientInterceptor.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/remoting/caucho/HessianClientInterceptor.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/remoting/caucho/HessianClientInterceptor.java 17 Aug 2012 15:16:14 -0000 1.1 @@ -0,0 +1,259 @@ +/* + * 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.remoting.caucho; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.UndeclaredThrowableException; +import java.net.ConnectException; +import java.net.MalformedURLException; + +import com.caucho.hessian.client.HessianProxyFactory; +import com.caucho.hessian.client.HessianRuntimeException; +import com.caucho.hessian.io.SerializerFactory; +import org.aopalliance.intercept.MethodInterceptor; +import org.aopalliance.intercept.MethodInvocation; + +import org.springframework.remoting.RemoteAccessException; +import org.springframework.remoting.RemoteConnectFailureException; +import org.springframework.remoting.RemoteLookupFailureException; +import org.springframework.remoting.RemoteProxyFailureException; +import org.springframework.remoting.support.UrlBasedRemoteAccessor; +import org.springframework.util.Assert; + +/** + * {@link org.aopalliance.intercept.MethodInterceptor} for accessing a Hessian service. + * Supports authentication via username and password. + * The service URL must be an HTTP URL exposing a Hessian service. + * + *

Hessian is a slim, binary RPC protocol. + * For information on Hessian, see the + * Hessian website + * + *

Note: There is no requirement for services accessed with this proxy factory + * to have been exported using Spring's {@link HessianServiceExporter}, as there is + * no special handling involved. As a consequence, you can also access services that + * have been exported using Caucho's {@link com.caucho.hessian.server.HessianServlet}. + * + * @author Juergen Hoeller + * @since 29.09.2003 + * @see #setServiceInterface + * @see #setServiceUrl + * @see #setUsername + * @see #setPassword + * @see HessianServiceExporter + * @see HessianProxyFactoryBean + * @see com.caucho.hessian.client.HessianProxyFactory + * @see com.caucho.hessian.server.HessianServlet + */ +public class HessianClientInterceptor extends UrlBasedRemoteAccessor implements MethodInterceptor { + + private HessianProxyFactory proxyFactory = new HessianProxyFactory(); + + private Object hessianProxy; + + + /** + * Set the HessianProxyFactory instance to use. + * If not specified, a default HessianProxyFactory will be created. + *

Allows to use an externally configured factory instance, + * in particular a custom HessianProxyFactory subclass. + */ + public void setProxyFactory(HessianProxyFactory proxyFactory) { + this.proxyFactory = (proxyFactory != null ? proxyFactory : new HessianProxyFactory()); + } + + /** + * Specify the Hessian SerializerFactory to use. + *

This will typically be passed in as an inner bean definition + * of type com.caucho.hessian.io.SerializerFactory, + * with custom bean property values applied. + */ + public void setSerializerFactory(SerializerFactory serializerFactory) { + this.proxyFactory.setSerializerFactory(serializerFactory); + } + + /** + * Set whether to send the Java collection type for each serialized + * collection. Default is "true". + */ + public void setSendCollectionType(boolean sendCollectionType) { + this.proxyFactory.getSerializerFactory().setSendCollectionType(sendCollectionType); + } + + /** + * Set whether overloaded methods should be enabled for remote invocations. + * Default is "false". + * @see com.caucho.hessian.client.HessianProxyFactory#setOverloadEnabled + */ + public void setOverloadEnabled(boolean overloadEnabled) { + this.proxyFactory.setOverloadEnabled(overloadEnabled); + } + + /** + * Set the username that this factory should use to access the remote service. + * Default is none. + *

The username will be sent by Hessian via HTTP Basic Authentication. + * @see com.caucho.hessian.client.HessianProxyFactory#setUser + */ + public void setUsername(String username) { + this.proxyFactory.setUser(username); + } + + /** + * Set the password that this factory should use to access the remote service. + * Default is none. + *

The password will be sent by Hessian via HTTP Basic Authentication. + * @see com.caucho.hessian.client.HessianProxyFactory#setPassword + */ + public void setPassword(String password) { + this.proxyFactory.setPassword(password); + } + + /** + * Set whether Hessian's debug mode should be enabled. + * Default is "false". + * @see com.caucho.hessian.client.HessianProxyFactory#setDebug + */ + public void setDebug(boolean debug) { + this.proxyFactory.setDebug(debug); + } + + /** + * Set whether to use a chunked post for sending a Hessian request. + * @see com.caucho.hessian.client.HessianProxyFactory#setChunkedPost + */ + public void setChunkedPost(boolean chunkedPost) { + this.proxyFactory.setChunkedPost(chunkedPost); + } + + /** + * Set the timeout to use when waiting for a reply from the Hessian service. + * @see com.caucho.hessian.client.HessianProxyFactory#setReadTimeout + */ + public void setReadTimeout(long timeout) { + this.proxyFactory.setReadTimeout(timeout); + } + + /** + * Set whether version 2 of the Hessian protocol should be used for + * parsing requests and replies. Default is "false". + * @see com.caucho.hessian.client.HessianProxyFactory#setHessian2Request + */ + public void setHessian2(boolean hessian2) { + this.proxyFactory.setHessian2Request(hessian2); + this.proxyFactory.setHessian2Reply(hessian2); + } + + /** + * Set whether version 2 of the Hessian protocol should be used for + * parsing requests. Default is "false". + * @see com.caucho.hessian.client.HessianProxyFactory#setHessian2Request + */ + public void setHessian2Request(boolean hessian2) { + this.proxyFactory.setHessian2Request(hessian2); + } + + /** + * Set whether version 2 of the Hessian protocol should be used for + * parsing replies. Default is "false". + * @see com.caucho.hessian.client.HessianProxyFactory#setHessian2Reply + */ + public void setHessian2Reply(boolean hessian2) { + this.proxyFactory.setHessian2Reply(hessian2); + } + + + public void afterPropertiesSet() { + super.afterPropertiesSet(); + prepare(); + } + + /** + * Initialize the Hessian proxy for this interceptor. + * @throws RemoteLookupFailureException if the service URL is invalid + */ + public void prepare() throws RemoteLookupFailureException { + try { + this.hessianProxy = createHessianProxy(this.proxyFactory); + } + catch (MalformedURLException ex) { + throw new RemoteLookupFailureException("Service URL [" + getServiceUrl() + "] is invalid", ex); + } + } + + /** + * Create the Hessian proxy that is wrapped by this interceptor. + * @param proxyFactory the proxy factory to use + * @return the Hessian proxy + * @throws MalformedURLException if thrown by the proxy factory + * @see com.caucho.hessian.client.HessianProxyFactory#create + */ + protected Object createHessianProxy(HessianProxyFactory proxyFactory) throws MalformedURLException { + Assert.notNull(getServiceInterface(), "'serviceInterface' is required"); + return proxyFactory.create(getServiceInterface(), getServiceUrl()); + } + + + public Object invoke(MethodInvocation invocation) throws Throwable { + if (this.hessianProxy == null) { + throw new IllegalStateException("HessianClientInterceptor is not properly initialized - " + + "invoke 'prepare' before attempting any operations"); + } + + ClassLoader originalClassLoader = overrideThreadContextClassLoader(); + try { + return invocation.getMethod().invoke(this.hessianProxy, invocation.getArguments()); + } + catch (InvocationTargetException ex) { + if (ex.getTargetException() instanceof HessianRuntimeException) { + HessianRuntimeException hre = (HessianRuntimeException) ex.getTargetException(); + Throwable rootCause = (hre.getRootCause() != null ? hre.getRootCause() : hre); + throw convertHessianAccessException(rootCause); + } + else if (ex.getTargetException() instanceof UndeclaredThrowableException) { + UndeclaredThrowableException utex = (UndeclaredThrowableException) ex.getTargetException(); + throw convertHessianAccessException(utex.getUndeclaredThrowable()); + } + throw ex.getTargetException(); + } + catch (Throwable ex) { + throw new RemoteProxyFailureException( + "Failed to invoke Hessian proxy for remote service [" + getServiceUrl() + "]", ex); + } + finally { + resetThreadContextClassLoader(originalClassLoader); + } + } + + /** + * Convert the given Hessian access exception to an appropriate + * Spring RemoteAccessException. + * @param ex the exception to convert + * @return the RemoteAccessException to throw + */ + protected RemoteAccessException convertHessianAccessException(Throwable ex) { + if (ex instanceof ConnectException) { + return new RemoteConnectFailureException( + "Cannot connect to Hessian remote service at [" + getServiceUrl() + "]", ex); + } + else { + return new RemoteAccessException( + "Cannot access Hessian remote service at [" + getServiceUrl() + "]", ex); + } + } + +} Index: 3rdParty_sources/spring/org/springframework/remoting/caucho/HessianExporter.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/remoting/caucho/HessianExporter.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/remoting/caucho/HessianExporter.java 17 Aug 2012 15:16:13 -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.remoting.caucho; + +import java.io.InputStream; +import java.io.OutputStream; +import java.lang.reflect.Constructor; + +import com.caucho.hessian.io.SerializerFactory; +import com.caucho.hessian.server.HessianSkeleton; +import org.apache.commons.logging.Log; + +import org.springframework.beans.factory.BeanInitializationException; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.remoting.support.RemoteExporter; +import org.springframework.util.Assert; +import org.springframework.util.ClassUtils; + +/** + * General stream-based protocol exporter for a Hessian endpoint. + * + *

Hessian is a slim, binary RPC protocol. + * For information on Hessian, see the + * Hessian website. + * + *

This exporter will work with both Hessian 2.x and 3.x (respectively + * Resin 2.x and 3.x), autodetecting the corresponding skeleton class. + * As of Spring 2.0, it is also compatible with the new Hessian 2 protocol + * (a.k.a. Hessian 3.0.20+), while remaining compatible with older versions. + * + * @author Juergen Hoeller + * @since 2.5.1 + * @see #invoke(java.io.InputStream, java.io.OutputStream) + * @see HessianServiceExporter + * @see SimpleHessianServiceExporter + */ +public class HessianExporter extends RemoteExporter implements InitializingBean { + + private static final boolean hessian2Available = + ClassUtils.isPresent("com.caucho.hessian.io.Hessian2Input", HessianServiceExporter.class.getClassLoader()); + + + private SerializerFactory serializerFactory = new SerializerFactory(); + + private Log debugLogger; + + private HessianSkeletonInvoker skeletonInvoker; + + + /** + * Specify the Hessian SerializerFactory to use. + *

This will typically be passed in as an inner bean definition + * of type com.caucho.hessian.io.SerializerFactory, + * with custom bean property values applied. + */ + public void setSerializerFactory(SerializerFactory serializerFactory) { + this.serializerFactory = (serializerFactory != null ? serializerFactory : new SerializerFactory()); + } + + /** + * Set whether to send the Java collection type for each serialized + * collection. Default is "true". + */ + public void setSendCollectionType(boolean sendCollectionType) { + this.serializerFactory.setSendCollectionType(sendCollectionType); + } + + /** + * Set whether Hessian's debug mode should be enabled, logging to + * this exporter's Commons Logging log. Default is "false". + * @see com.caucho.hessian.client.HessianProxyFactory#setDebug + */ + public void setDebug(boolean debug) { + this.debugLogger = (debug ? logger : null); + } + + + public void afterPropertiesSet() { + prepare(); + } + + /** + * Initialize this exporter. + */ + public void prepare() { + HessianSkeleton skeleton = null; + + try { + try { + // Try Hessian 3.x (with service interface argument). + Constructor ctor = HessianSkeleton.class.getConstructor(new Class[] {Object.class, Class.class}); + checkService(); + checkServiceInterface(); + skeleton = (HessianSkeleton) + ctor.newInstance(new Object[] {getProxyForService(), getServiceInterface()}); + } + catch (NoSuchMethodException ex) { + // Fall back to Hessian 2.x (without service interface argument). + Constructor ctor = HessianSkeleton.class.getConstructor(new Class[] {Object.class}); + skeleton = (HessianSkeleton) ctor.newInstance(new Object[] {getProxyForService()}); + } + } + catch (Throwable ex) { + throw new BeanInitializationException("Hessian skeleton initialization failed", ex); + } + + if (hessian2Available) { + // Hessian 2 (version 3.0.20+). + this.skeletonInvoker = new Hessian2SkeletonInvoker(skeleton, this.serializerFactory, this.debugLogger); + } + else { + // Hessian 1 (version 3.0.19-). + this.skeletonInvoker = new Hessian1SkeletonInvoker(skeleton, this.serializerFactory); + } + } + + + /** + * Perform an invocation on the exported object. + * @param inputStream the request stream + * @param outputStream the response stream + * @throws Throwable if invocation failed + */ + public void invoke(InputStream inputStream, OutputStream outputStream) throws Throwable { + Assert.notNull(this.skeletonInvoker, "Hessian exporter has not been initialized"); + ClassLoader originalClassLoader = overrideThreadContextClassLoader(); + try { + this.skeletonInvoker.invoke(inputStream, outputStream); + } + finally { + resetThreadContextClassLoader(originalClassLoader); + } + } + +} Index: 3rdParty_sources/spring/org/springframework/remoting/caucho/HessianProxyFactoryBean.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/remoting/caucho/HessianProxyFactoryBean.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/remoting/caucho/HessianProxyFactoryBean.java 17 Aug 2012 15:16:13 -0000 1.1 @@ -0,0 +1,66 @@ +/* + * 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.remoting.caucho; + +import org.springframework.aop.framework.ProxyFactory; +import org.springframework.beans.factory.FactoryBean; + +/** + * FactoryBean for Hessian proxies. Exposes the proxied service for + * use as a bean reference, using the specified service interface. + * + *

Hessian is a slim, binary RPC protocol. + * For information on Hessian, see the + * Hessian website + * + *

The service URL must be an HTTP URL exposing a Hessian service. + * For details, see the {@link HessianClientInterceptor} javadoc. + * + * @author Juergen Hoeller + * @since 13.05.2003 + * @see #setServiceInterface + * @see #setServiceUrl + * @see HessianClientInterceptor + * @see HessianServiceExporter + * @see org.springframework.remoting.caucho.BurlapProxyFactoryBean + * @see org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean + * @see org.springframework.remoting.rmi.RmiProxyFactoryBean + */ +public class HessianProxyFactoryBean extends HessianClientInterceptor implements FactoryBean { + + private Object serviceProxy; + + + public void afterPropertiesSet() { + super.afterPropertiesSet(); + this.serviceProxy = new ProxyFactory(getServiceInterface(), this).getProxy(getBeanClassLoader()); + } + + + public Object getObject() { + return this.serviceProxy; + } + + public Class getObjectType() { + return getServiceInterface(); + } + + public boolean isSingleton() { + return true; + } + +} Index: 3rdParty_sources/spring/org/springframework/remoting/caucho/HessianServiceExporter.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/remoting/caucho/HessianServiceExporter.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/remoting/caucho/HessianServiceExporter.java 17 Aug 2012 15:16:13 -0000 1.1 @@ -0,0 +1,77 @@ +/* + * 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.remoting.caucho; + +import java.io.IOException; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.springframework.web.HttpRequestHandler; +import org.springframework.web.HttpRequestMethodNotSupportedException; +import org.springframework.web.util.NestedServletException; + +/** + * Servlet-API-based HTTP request handler that exports the specified service bean + * as Hessian service endpoint, accessible via a Hessian proxy. + * + *

Note: Spring also provides an alternative version of this exporter, + * for Sun's JRE 1.6 HTTP server: {@link SimpleHessianServiceExporter}. + * + *

Hessian is a slim, binary RPC protocol. + * For information on Hessian, see the + * Hessian website. + * + *

This exporter will work with both Hessian 2.x and 3.x (respectively + * Resin 2.x and 3.x), autodetecting the corresponding skeleton class. + * As of Spring 2.0, it is also compatible with the new Hessian 2 protocol + * (a.k.a. Hessian 3.0.20+), while remaining compatible with older versions. + * + *

Note: Hessian services exported with this class can be accessed by + * any Hessian client, as there isn't any special handling involved. + * + * @author Juergen Hoeller + * @since 13.05.2003 + * @see HessianClientInterceptor + * @see HessianProxyFactoryBean + * @see org.springframework.remoting.caucho.BurlapServiceExporter + * @see org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter + * @see org.springframework.remoting.rmi.RmiServiceExporter + */ +public class HessianServiceExporter extends HessianExporter implements HttpRequestHandler { + + /** + * Processes the incoming Hessian request and creates a Hessian response. + */ + public void handleRequest(HttpServletRequest request, HttpServletResponse response) + throws ServletException, IOException { + + if (!"POST".equals(request.getMethod())) { + throw new HttpRequestMethodNotSupportedException(request.getMethod(), + new String[] {"POST"}, "HessianServiceExporter only supports POST requests"); + } + + try { + invoke(request.getInputStream(), response.getOutputStream()); + } + catch (Throwable ex) { + throw new NestedServletException("Hessian skeleton invocation failed", ex); + } + } + +} Index: 3rdParty_sources/spring/org/springframework/remoting/caucho/HessianSkeletonInvoker.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/remoting/caucho/HessianSkeletonInvoker.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/remoting/caucho/HessianSkeletonInvoker.java 17 Aug 2012 15:16:14 -0000 1.1 @@ -0,0 +1,67 @@ +/* + * 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.remoting.caucho; + +import java.io.InputStream; +import java.io.OutputStream; + +import com.caucho.hessian.server.HessianSkeleton; +import com.caucho.hessian.io.SerializerFactory; + +import org.springframework.util.Assert; + +/** + * Internal invoker strategy for a Hessian skeleton. + * Allows for common handling of Hessian protocol version 1 and 2. + * + * @author Juergen Hoeller + * @since 2.0 + */ +abstract class HessianSkeletonInvoker { + + /** + * Wrapped HessianSkeleton, available to subclasses. + */ + protected final HessianSkeleton skeleton; + + /** + * Hessian SerializerFactory (if any), available to subclasses. + */ + protected final SerializerFactory serializerFactory; + + + /** + * Create a new HessianSkeletonInvoker for the given skeleton. + * @param skeleton the HessianSkeleton to wrap + * @param serializerFactory the Hessian SerializerFactory to use, if any + */ + public HessianSkeletonInvoker(HessianSkeleton skeleton, SerializerFactory serializerFactory) { + Assert.notNull(skeleton, "HessianSkeleton must not be null"); + this.skeleton = skeleton; + this.serializerFactory = serializerFactory; + } + + + /** + * Invoke the given skeleton based on the given input/output streams. + * @param inputStream the stream containing the Hessian input + * @param outputStream the stream to receive the Hessian output + * @throws Throwable if the skeleton invocation failed + */ + public abstract void invoke(InputStream inputStream, OutputStream outputStream) throws Throwable; + +} Index: 3rdParty_sources/spring/org/springframework/remoting/caucho/SimpleBurlapServiceExporter.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/remoting/caucho/SimpleBurlapServiceExporter.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/remoting/caucho/SimpleBurlapServiceExporter.java 17 Aug 2012 15:16:13 -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.remoting.caucho; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; + +import com.sun.net.httpserver.HttpExchange; +import com.sun.net.httpserver.HttpHandler; + +import org.springframework.util.FileCopyUtils; + +/** + * HTTP request handler that exports the specified service bean as + * Burlap service endpoint, accessible via a Burlap proxy. + * Designed for Sun's JRE 1.6 HTTP server, implementing the + * {@link com.sun.net.httpserver.HttpHandler} interface. + * + *

Burlap is a slim, XML-based RPC protocol. + * For information on Burlap, see the + * Burlap website. + * This exporter requires Burlap 3.x. + * + *

Note: Burlap services exported with this class can be accessed by + * any Burlap client, as there isn't any special handling involved. + * + * @author Juergen Hoeller + * @since 2.5.1 + * @see org.springframework.remoting.caucho.BurlapClientInterceptor + * @see org.springframework.remoting.caucho.BurlapProxyFactoryBean + * @see SimpleHessianServiceExporter + * @see org.springframework.remoting.httpinvoker.SimpleHttpInvokerServiceExporter + */ +public class SimpleBurlapServiceExporter extends BurlapExporter implements HttpHandler { + + /** + * Processes the incoming Burlap request and creates a Burlap response. + */ + public void handle(HttpExchange exchange) throws IOException { + if (!"POST".equals(exchange.getRequestMethod())) { + exchange.getResponseHeaders().set("Allow", "POST"); + exchange.sendResponseHeaders(405, -1); + return; + } + + ByteArrayOutputStream output = new ByteArrayOutputStream(1024); + try { + invoke(exchange.getRequestBody(), output); + } + catch (Throwable ex) { + exchange.sendResponseHeaders(500, -1); + throw new IOException("Burlap skeleton invocation failed", ex); + } + + exchange.sendResponseHeaders(200, output.size()); + FileCopyUtils.copy(output.toByteArray(), exchange.getResponseBody()); + } + +} Index: 3rdParty_sources/spring/org/springframework/remoting/caucho/SimpleHessianServiceExporter.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/remoting/caucho/SimpleHessianServiceExporter.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/remoting/caucho/SimpleHessianServiceExporter.java 17 Aug 2012 15:16:13 -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.remoting.caucho; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; + +import com.sun.net.httpserver.HttpExchange; +import com.sun.net.httpserver.HttpHandler; + +import org.springframework.util.FileCopyUtils; + +/** + * HTTP request handler that exports the specified service bean as + * Hessian service endpoint, accessible via a Hessian proxy. + * Designed for Sun's JRE 1.6 HTTP server, implementing the + * {@link com.sun.net.httpserver.HttpHandler} interface. + * + *

Hessian is a slim, binary RPC protocol. + * For information on Hessian, see the + * Hessian website. + * This exporter requires Hessian 3.0.20 or above. + * + *

Note: Hessian services exported with this class can be accessed by + * any Hessian client, as there isn't any special handling involved. + * + * @author Juergen Hoeller + * @since 2.5.1 + * @see org.springframework.remoting.caucho.HessianClientInterceptor + * @see org.springframework.remoting.caucho.HessianProxyFactoryBean + * @see SimpleBurlapServiceExporter + * @see org.springframework.remoting.httpinvoker.SimpleHttpInvokerServiceExporter + */ +public class SimpleHessianServiceExporter extends HessianExporter implements HttpHandler { + + /** + * Processes the incoming Hessian request and creates a Hessian response. + */ + public void handle(HttpExchange exchange) throws IOException { + if (!"POST".equals(exchange.getRequestMethod())) { + exchange.getResponseHeaders().set("Allow", "POST"); + exchange.sendResponseHeaders(405, -1); + return; + } + + ByteArrayOutputStream output = new ByteArrayOutputStream(1024); + try { + invoke(exchange.getRequestBody(), output); + } + catch (Throwable ex) { + exchange.sendResponseHeaders(500, -1); + throw new IOException("Hessian skeleton invocation failed", ex); + } + + exchange.sendResponseHeaders(200, output.size()); + FileCopyUtils.copy(output.toByteArray(), exchange.getResponseBody()); + } + +} Index: 3rdParty_sources/spring/org/springframework/remoting/caucho/package.html =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/remoting/caucho/package.html,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/remoting/caucho/package.html 17 Aug 2012 15:16:14 -0000 1.1 @@ -0,0 +1,17 @@ + + + +This package provides remoting classes for Caucho's Hessian and Burlap +protocols: a proxy factory for accessing Hessian/Burlap services, +and an exporter for making beans available to Hessian/Burlap clients. + +

Hessian is a slim, binary RPC protocol over HTTP. +For information on Hessian, see the +Hessian website + +

Burlap is a slim, XML-based RPC protocol over HTTP. +For information on Burlap, see the +Burlap website + + + Index: 3rdParty_sources/spring/org/springframework/remoting/httpinvoker/AbstractHttpInvokerRequestExecutor.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/remoting/httpinvoker/AbstractHttpInvokerRequestExecutor.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/remoting/httpinvoker/AbstractHttpInvokerRequestExecutor.java 17 Aug 2012 15:16:05 -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.remoting.httpinvoker; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.OutputStream; +import java.rmi.RemoteException; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import org.springframework.beans.factory.BeanClassLoaderAware; +import org.springframework.remoting.rmi.CodebaseAwareObjectInputStream; +import org.springframework.remoting.support.RemoteInvocation; +import org.springframework.remoting.support.RemoteInvocationResult; +import org.springframework.util.Assert; + +/** + * Abstract base implementation of the HttpInvokerRequestExecutor interface. + * + *

Pre-implements serialization of RemoteInvocation objects and + * deserialization of RemoteInvocationResults objects. + * + * @author Juergen Hoeller + * @since 1.1 + * @see #doExecuteRequest + */ +public abstract class AbstractHttpInvokerRequestExecutor + implements HttpInvokerRequestExecutor, BeanClassLoaderAware { + + /** + * Default content type: "application/x-java-serialized-object" + */ + public static final String CONTENT_TYPE_SERIALIZED_OBJECT = "application/x-java-serialized-object"; + + + protected static final String HTTP_METHOD_POST = "POST"; + + protected static final String HTTP_HEADER_ACCEPT_LANGUAGE = "Accept-Language"; + + protected static final String HTTP_HEADER_ACCEPT_ENCODING = "Accept-Encoding"; + + protected static final String HTTP_HEADER_CONTENT_ENCODING = "Content-Encoding"; + + protected static final String HTTP_HEADER_CONTENT_TYPE = "Content-Type"; + + protected static final String HTTP_HEADER_CONTENT_LENGTH = "Content-Length"; + + protected static final String ENCODING_GZIP = "gzip"; + + + private static final int SERIALIZED_INVOCATION_BYTE_ARRAY_INITIAL_SIZE = 1024; + + + protected final Log logger = LogFactory.getLog(getClass()); + + private String contentType = CONTENT_TYPE_SERIALIZED_OBJECT; + + private boolean acceptGzipEncoding = true; + + private ClassLoader beanClassLoader; + + + /** + * Specify the content type to use for sending HTTP invoker requests. + *

Default is "application/x-java-serialized-object". + */ + public void setContentType(String contentType) { + Assert.notNull(contentType, "'contentType' must not be null"); + this.contentType = contentType; + } + + /** + * Return the content type to use for sending HTTP invoker requests. + */ + public String getContentType() { + return this.contentType; + } + + /** + * Set whether to accept GZIP encoding, that is, whether to + * send the HTTP "Accept-Encoding" header with "gzip" as value. + *

Default is "true". Turn this flag off if you do not want + * GZIP response compression even if enabled on the HTTP server. + */ + public void setAcceptGzipEncoding(boolean acceptGzipEncoding) { + this.acceptGzipEncoding = acceptGzipEncoding; + } + + /** + * Return whether to accept GZIP encoding, that is, whether to + * send the HTTP "Accept-Encoding" header with "gzip" as value. + */ + public boolean isAcceptGzipEncoding() { + return this.acceptGzipEncoding; + } + + public void setBeanClassLoader(ClassLoader classLoader) { + this.beanClassLoader = classLoader; + } + + /** + * Return the bean ClassLoader that this executor is supposed to use. + */ + protected ClassLoader getBeanClassLoader() { + return this.beanClassLoader; + } + + + public final RemoteInvocationResult executeRequest( + HttpInvokerClientConfiguration config, RemoteInvocation invocation) throws Exception { + + ByteArrayOutputStream baos = getByteArrayOutputStream(invocation); + if (logger.isDebugEnabled()) { + logger.debug("Sending HTTP invoker request for service at [" + config.getServiceUrl() + + "], with size " + baos.size()); + } + return doExecuteRequest(config, baos); + } + + /** + * Serialize the given RemoteInvocation into a ByteArrayOutputStream. + * @param invocation the RemoteInvocation object + * @return a ByteArrayOutputStream with the serialized RemoteInvocation + * @throws IOException if thrown by I/O methods + */ + protected ByteArrayOutputStream getByteArrayOutputStream(RemoteInvocation invocation) throws IOException { + ByteArrayOutputStream baos = new ByteArrayOutputStream(SERIALIZED_INVOCATION_BYTE_ARRAY_INITIAL_SIZE); + writeRemoteInvocation(invocation, baos); + return baos; + } + + /** + * Serialize the given RemoteInvocation to the given OutputStream. + *

The default implementation gives decorateOutputStream a chance + * to decorate the stream first (for example, for custom encryption or compression). + * Creates an ObjectOutputStream for the final stream and calls + * doWriteRemoteInvocation to actually write the object. + *

Can be overridden for custom serialization of the invocation. + * @param invocation the RemoteInvocation object + * @param os the OutputStream to write to + * @throws IOException if thrown by I/O methods + * @see #decorateOutputStream + * @see #doWriteRemoteInvocation + */ + protected void writeRemoteInvocation(RemoteInvocation invocation, OutputStream os) throws IOException { + ObjectOutputStream oos = new ObjectOutputStream(decorateOutputStream(os)); + try { + doWriteRemoteInvocation(invocation, oos); + oos.flush(); + } + finally { + oos.close(); + } + } + + /** + * Return the OutputStream to use for writing remote invocations, + * potentially decorating the given original OutputStream. + *

The default implementation returns the given stream as-is. + * Can be overridden, for example, for custom encryption or compression. + * @param os the original OutputStream + * @return the potentially decorated OutputStream + */ + protected OutputStream decorateOutputStream(OutputStream os) throws IOException { + return os; + } + + /** + * Perform the actual writing of the given invocation object to the + * given ObjectOutputStream. + *

The default implementation simply calls writeObject. + * Can be overridden for serialization of a custom wrapper object rather + * than the plain invocation, for example an encryption-aware holder. + * @param invocation the RemoteInvocation object + * @param oos the ObjectOutputStream to write to + * @throws IOException if thrown by I/O methods + * @see java.io.ObjectOutputStream#writeObject + */ + protected void doWriteRemoteInvocation(RemoteInvocation invocation, ObjectOutputStream oos) throws IOException { + oos.writeObject(invocation); + } + + + /** + * Execute a request to send the given serialized remote invocation. + *

Implementations will usually call readRemoteInvocationResult + * to deserialize a returned RemoteInvocationResult object. + * @param config the HTTP invoker configuration that specifies the + * target service + * @param baos the ByteArrayOutputStream that contains the serialized + * RemoteInvocation object + * @return the RemoteInvocationResult object + * @throws IOException if thrown by I/O operations + * @throws ClassNotFoundException if thrown during deserialization + * @throws Exception in case of general errors + * @see #readRemoteInvocationResult(java.io.InputStream, String) + */ + protected abstract RemoteInvocationResult doExecuteRequest( + HttpInvokerClientConfiguration config, ByteArrayOutputStream baos) + throws Exception; + + /** + * Deserialize a RemoteInvocationResult object from the given InputStream. + *

Gives decorateInputStream a chance to decorate the stream + * first (for example, for custom encryption or compression). Creates an + * ObjectInputStream via createObjectInputStream and + * calls doReadRemoteInvocationResult to actually read the object. + *

Can be overridden for custom serialization of the invocation. + * @param is the InputStream to read from + * @param codebaseUrl the codebase URL to load classes from if not found locally + * @return the RemoteInvocationResult object + * @throws IOException if thrown by I/O methods + * @throws ClassNotFoundException if thrown during deserialization + * @see #decorateInputStream + * @see #createObjectInputStream + * @see #doReadRemoteInvocationResult + */ + protected RemoteInvocationResult readRemoteInvocationResult(InputStream is, String codebaseUrl) + throws IOException, ClassNotFoundException { + + ObjectInputStream ois = createObjectInputStream(decorateInputStream(is), codebaseUrl); + try { + return doReadRemoteInvocationResult(ois); + } + finally { + ois.close(); + } + } + + /** + * Return the InputStream to use for reading remote invocation results, + * potentially decorating the given original InputStream. + *

The default implementation returns the given stream as-is. + * Can be overridden, for example, for custom encryption or compression. + * @param is the original InputStream + * @return the potentially decorated InputStream + */ + protected InputStream decorateInputStream(InputStream is) throws IOException { + return is; + } + + /** + * Create an ObjectInputStream for the given InputStream and codebase. + * The default implementation creates a CodebaseAwareObjectInputStream. + * @param is the InputStream to read from + * @param codebaseUrl the codebase URL to load classes from if not found locally + * (can be null) + * @return the new ObjectInputStream instance to use + * @throws IOException if creation of the ObjectInputStream failed + * @see org.springframework.remoting.rmi.CodebaseAwareObjectInputStream + */ + protected ObjectInputStream createObjectInputStream(InputStream is, String codebaseUrl) throws IOException { + return new CodebaseAwareObjectInputStream(is, getBeanClassLoader(), codebaseUrl); + } + + /** + * Perform the actual reading of an invocation object from the + * given ObjectInputStream. + *

The default implementation simply calls readObject. + * Can be overridden for deserialization of a custom wrapper object rather + * than the plain invocation, for example an encryption-aware holder. + * @param ois the ObjectInputStream to read from + * @return the RemoteInvocationResult object + * @throws IOException if thrown by I/O methods + * @throws ClassNotFoundException if the class name of a serialized object + * couldn't get resolved + * @see java.io.ObjectOutputStream#writeObject + */ + protected RemoteInvocationResult doReadRemoteInvocationResult(ObjectInputStream ois) + throws IOException, ClassNotFoundException { + + Object obj = ois.readObject(); + if (!(obj instanceof RemoteInvocationResult)) { + throw new RemoteException("Deserialized object needs to be assignable to type [" + + RemoteInvocationResult.class.getName() + "]: " + obj); + } + return (RemoteInvocationResult) obj; + } + +} Index: 3rdParty_sources/spring/org/springframework/remoting/httpinvoker/CommonsHttpInvokerRequestExecutor.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/remoting/httpinvoker/CommonsHttpInvokerRequestExecutor.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/remoting/httpinvoker/CommonsHttpInvokerRequestExecutor.java 17 Aug 2012 15:16:05 -0000 1.1 @@ -0,0 +1,258 @@ +/* + * 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.remoting.httpinvoker; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.zip.GZIPInputStream; + +import org.apache.commons.httpclient.Header; +import org.apache.commons.httpclient.HttpClient; +import org.apache.commons.httpclient.HttpException; +import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager; +import org.apache.commons.httpclient.methods.ByteArrayRequestEntity; +import org.apache.commons.httpclient.methods.PostMethod; + +import org.springframework.context.i18n.LocaleContext; +import org.springframework.context.i18n.LocaleContextHolder; +import org.springframework.remoting.support.RemoteInvocationResult; +import org.springframework.util.StringUtils; + +/** + * {@link HttpInvokerRequestExecutor} implementation that uses + * Jakarta Commons HttpClient + * to execute POST requests. Requires Commons HttpClient 3.0 or higher. + * + *

Allows to use a pre-configured {@link org.apache.commons.httpclient.HttpClient} + * instance, potentially with authentication, HTTP connection pooling, etc. + * Also designed for easy subclassing, providing specific template methods. + * + * @author Juergen Hoeller + * @author Mark Fisher + * @since 1.1 + * @see SimpleHttpInvokerRequestExecutor + */ +public class CommonsHttpInvokerRequestExecutor extends AbstractHttpInvokerRequestExecutor { + + /** + * Default timeout value if no HttpClient is explicitly provided. + */ + private static final int DEFAULT_READ_TIMEOUT_MILLISECONDS = (60 * 1000); + + private HttpClient httpClient; + + + /** + * Create a new CommonsHttpInvokerRequestExecutor with a default + * HttpClient that uses a default MultiThreadedHttpConnectionManager. + * Sets the socket read timeout to {@link #DEFAULT_READ_TIMEOUT_MILLISECONDS}. + * @see org.apache.commons.httpclient.HttpClient + * @see org.apache.commons.httpclient.MultiThreadedHttpConnectionManager + */ + public CommonsHttpInvokerRequestExecutor() { + this.httpClient = new HttpClient(new MultiThreadedHttpConnectionManager()); + this.setReadTimeout(DEFAULT_READ_TIMEOUT_MILLISECONDS); + } + + /** + * Create a new CommonsHttpInvokerRequestExecutor with the given + * HttpClient instance. The socket read timeout of the provided + * HttpClient will not be changed. + * @param httpClient the HttpClient instance to use for this request executor + */ + public CommonsHttpInvokerRequestExecutor(HttpClient httpClient) { + this.httpClient = httpClient; + } + + + /** + * Set the HttpClient instance to use for this request executor. + */ + public void setHttpClient(HttpClient httpClient) { + this.httpClient = httpClient; + } + + /** + * Return the HttpClient instance that this request executor uses. + */ + public HttpClient getHttpClient() { + return this.httpClient; + } + + /** + * Set the socket read timeout for the underlying HttpClient. A value + * of 0 means never timeout. + * @param timeout the timeout value in milliseconds + * @see org.apache.commons.httpclient.params.HttpConnectionManagerParams#setSoTimeout(int) + * @see #DEFAULT_READ_TIMEOUT_MILLISECONDS + */ + public void setReadTimeout(int timeout) { + if (timeout < 0) { + throw new IllegalArgumentException("timeout must be a non-negative value"); + } + this.httpClient.getHttpConnectionManager().getParams().setSoTimeout(timeout); + } + + + /** + * Execute the given request through Commons HttpClient. + *

This method implements the basic processing workflow: + * The actual work happens in this class's template methods. + * @see #createPostMethod + * @see #setRequestBody + * @see #executePostMethod + * @see #validateResponse + * @see #getResponseBody + */ + protected RemoteInvocationResult doExecuteRequest( + HttpInvokerClientConfiguration config, ByteArrayOutputStream baos) + throws IOException, ClassNotFoundException { + + PostMethod postMethod = createPostMethod(config); + try { + setRequestBody(config, postMethod, baos); + executePostMethod(config, getHttpClient(), postMethod); + validateResponse(config, postMethod); + InputStream responseBody = getResponseBody(config, postMethod); + return readRemoteInvocationResult(responseBody, config.getCodebaseUrl()); + } + finally { + // Need to explicitly release because it might be pooled. + postMethod.releaseConnection(); + } + } + + /** + * Create a PostMethod for the given configuration. + *

The default implementation creates a standard PostMethod with + * "application/x-java-serialized-object" as "Content-Type" header. + * @param config the HTTP invoker configuration that specifies the + * target service + * @return the PostMethod instance + * @throws IOException if thrown by I/O methods + */ + protected PostMethod createPostMethod(HttpInvokerClientConfiguration config) throws IOException { + PostMethod postMethod = new PostMethod(config.getServiceUrl()); + LocaleContext locale = LocaleContextHolder.getLocaleContext(); + if (locale != null) { + postMethod.addRequestHeader(HTTP_HEADER_ACCEPT_LANGUAGE, StringUtils.toLanguageTag(locale.getLocale())); + } + if (isAcceptGzipEncoding()) { + postMethod.addRequestHeader(HTTP_HEADER_ACCEPT_ENCODING, ENCODING_GZIP); + } + return postMethod; + } + + /** + * Set the given serialized remote invocation as request body. + *

The default implementation simply sets the serialized invocation + * as the PostMethod's request body. This can be overridden, for example, + * to write a specific encoding and potentially set appropriate HTTP + * request headers. + * @param config the HTTP invoker configuration that specifies the target service + * @param postMethod the PostMethod to set the request body on + * @param baos the ByteArrayOutputStream that contains the serialized + * RemoteInvocation object + * @throws IOException if thrown by I/O methods + * @see org.apache.commons.httpclient.methods.PostMethod#setRequestBody(java.io.InputStream) + * @see org.apache.commons.httpclient.methods.PostMethod#setRequestEntity + * @see org.apache.commons.httpclient.methods.InputStreamRequestEntity + */ + protected void setRequestBody( + HttpInvokerClientConfiguration config, PostMethod postMethod, ByteArrayOutputStream baos) + throws IOException { + + postMethod.setRequestEntity(new ByteArrayRequestEntity(baos.toByteArray(), getContentType())); + } + + /** + * Execute the given PostMethod instance. + * @param config the HTTP invoker configuration that specifies the target service + * @param httpClient the HttpClient to execute on + * @param postMethod the PostMethod to execute + * @throws IOException if thrown by I/O methods + * @see org.apache.commons.httpclient.HttpClient#executeMethod(org.apache.commons.httpclient.HttpMethod) + */ + protected void executePostMethod( + HttpInvokerClientConfiguration config, HttpClient httpClient, PostMethod postMethod) + throws IOException { + + httpClient.executeMethod(postMethod); + } + + /** + * Validate the given response as contained in the PostMethod object, + * throwing an exception if it does not correspond to a successful HTTP response. + *

Default implementation rejects any HTTP status code beyond 2xx, to avoid + * parsing the response body and trying to deserialize from a corrupted stream. + * @param config the HTTP invoker configuration that specifies the target service + * @param postMethod the executed PostMethod to validate + * @throws IOException if validation failed + * @see org.apache.commons.httpclient.methods.PostMethod#getStatusCode() + * @see org.apache.commons.httpclient.HttpException + */ + protected void validateResponse(HttpInvokerClientConfiguration config, PostMethod postMethod) + throws IOException { + + if (postMethod.getStatusCode() >= 300) { + throw new HttpException( + "Did not receive successful HTTP response: status code = " + postMethod.getStatusCode() + + ", status message = [" + postMethod.getStatusText() + "]"); + } + } + + /** + * Extract the response body from the given executed remote invocation + * request. + *

The default implementation simply fetches the PostMethod's response + * body stream. If the response is recognized as GZIP response, the + * InputStream will get wrapped in a GZIPInputStream. + * @param config the HTTP invoker configuration that specifies the target service + * @param postMethod the PostMethod to read the response body from + * @return an InputStream for the response body + * @throws IOException if thrown by I/O methods + * @see #isGzipResponse + * @see java.util.zip.GZIPInputStream + * @see org.apache.commons.httpclient.methods.PostMethod#getResponseBodyAsStream() + * @see org.apache.commons.httpclient.methods.PostMethod#getResponseHeader(String) + */ + protected InputStream getResponseBody(HttpInvokerClientConfiguration config, PostMethod postMethod) + throws IOException { + + if (isGzipResponse(postMethod)) { + return new GZIPInputStream(postMethod.getResponseBodyAsStream()); + } + else { + return postMethod.getResponseBodyAsStream(); + } + } + + /** + * Determine whether the given response indicates a GZIP response. + *

Default implementation checks whether the HTTP "Content-Encoding" + * header contains "gzip" (in any casing). + * @param postMethod the PostMethod to check + * @return whether the given response indicates a GZIP response + */ + protected boolean isGzipResponse(PostMethod postMethod) { + Header encodingHeader = postMethod.getResponseHeader(HTTP_HEADER_CONTENT_ENCODING); + return (encodingHeader != null && encodingHeader.getValue() != null && + encodingHeader.getValue().toLowerCase().indexOf(ENCODING_GZIP) != -1); + } + +} Index: 3rdParty_sources/spring/org/springframework/remoting/httpinvoker/HttpInvokerClientConfiguration.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/remoting/httpinvoker/HttpInvokerClientConfiguration.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/remoting/httpinvoker/HttpInvokerClientConfiguration.java 17 Aug 2012 15:16:04 -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.remoting.httpinvoker; + +/** + * Configuration interface for executing HTTP invoker requests. + * + * @author Juergen Hoeller + * @since 1.1 + * @see HttpInvokerRequestExecutor + * @see HttpInvokerClientInterceptor + */ +public interface HttpInvokerClientConfiguration { + + /** + * Return the HTTP URL of the target service. + */ + String getServiceUrl(); + + /** + * Return the codebase URL to download classes from if not found locally. + * Can consist of multiple URLs, separated by spaces. + * @return the codebase URL, or null if none + * @see java.rmi.server.RMIClassLoader + */ + String getCodebaseUrl(); + +} Index: 3rdParty_sources/spring/org/springframework/remoting/httpinvoker/HttpInvokerClientInterceptor.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/remoting/httpinvoker/HttpInvokerClientInterceptor.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/remoting/httpinvoker/HttpInvokerClientInterceptor.java 17 Aug 2012 15:16:05 -0000 1.1 @@ -0,0 +1,216 @@ +/* + * 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.remoting.httpinvoker; + +import java.io.IOException; +import java.io.InvalidClassException; +import java.net.ConnectException; + +import org.aopalliance.intercept.MethodInterceptor; +import org.aopalliance.intercept.MethodInvocation; + +import org.springframework.aop.support.AopUtils; +import org.springframework.remoting.RemoteAccessException; +import org.springframework.remoting.RemoteConnectFailureException; +import org.springframework.remoting.RemoteInvocationFailureException; +import org.springframework.remoting.support.RemoteInvocation; +import org.springframework.remoting.support.RemoteInvocationBasedAccessor; +import org.springframework.remoting.support.RemoteInvocationResult; + +/** + * {@link org.aopalliance.intercept.MethodInterceptor} for accessing an + * HTTP invoker service. The service URL must be an HTTP URL exposing + * an HTTP invoker service. + * + *

Serializes remote invocation objects and deserializes remote invocation + * result objects. Uses Java serialization just like RMI, but provides the + * same ease of setup as Caucho's HTTP-based Hessian and Burlap protocols. + * + *

HTTP invoker is a very extensible and customizable protocol. + * It supports the RemoteInvocationFactory mechanism, like RMI invoker, + * allowing to include additional invocation attributes (for example, + * a security context). Furthermore, it allows to customize request + * execution via the {@link HttpInvokerRequestExecutor} strategy. + * + *

Can use the JDK's {@link java.rmi.server.RMIClassLoader} to load + * classes from a given {@link #setCodebaseUrl codebase}, performing + * on-demand dynamic code download from a remote location. The codebase + * can consist of multiple URLs, separated by spaces. Note that + * RMIClassLoader requires a SecurityManager to be set, analogous to + * when using dynamic class download with standard RMI! + * (See the RMI documentation for details.) + * + * @author Juergen Hoeller + * @since 1.1 + * @see #setServiceUrl + * @see #setCodebaseUrl + * @see #setRemoteInvocationFactory + * @see #setHttpInvokerRequestExecutor + * @see HttpInvokerServiceExporter + * @see HttpInvokerProxyFactoryBean + * @see java.rmi.server.RMIClassLoader + */ +public class HttpInvokerClientInterceptor extends RemoteInvocationBasedAccessor + implements MethodInterceptor, HttpInvokerClientConfiguration { + + private String codebaseUrl; + + private HttpInvokerRequestExecutor httpInvokerRequestExecutor; + + + /** + * Set the codebase URL to download classes from if not found locally. + * Can consists of multiple URLs, separated by spaces. + *

Follows RMI's codebase conventions for dynamic class download. + * In contrast to RMI, where the server determines the URL for class download + * (via the "java.rmi.server.codebase" system property), it's the client + * that determines the codebase URL here. The server will usually be the + * same as for the service URL, just pointing to a different path there. + * @see #setServiceUrl + * @see org.springframework.remoting.rmi.CodebaseAwareObjectInputStream + * @see java.rmi.server.RMIClassLoader + */ + public void setCodebaseUrl(String codebaseUrl) { + this.codebaseUrl = codebaseUrl; + } + + /** + * Return the codebase URL to download classes from if not found locally. + */ + public String getCodebaseUrl() { + return this.codebaseUrl; + } + + /** + * Set the HttpInvokerRequestExecutor implementation to use for executing + * remote invocations. + *

Default is {@link SimpleHttpInvokerRequestExecutor}. Alternatively, + * consider using {@link CommonsHttpInvokerRequestExecutor} for more + * sophisticated needs. + * @see SimpleHttpInvokerRequestExecutor + * @see CommonsHttpInvokerRequestExecutor + */ + public void setHttpInvokerRequestExecutor(HttpInvokerRequestExecutor httpInvokerRequestExecutor) { + this.httpInvokerRequestExecutor = httpInvokerRequestExecutor; + } + + /** + * Return the HttpInvokerRequestExecutor used by this remote accessor. + *

Creates a default SimpleHttpInvokerRequestExecutor if no executor + * has been initialized already. + */ + public HttpInvokerRequestExecutor getHttpInvokerRequestExecutor() { + if (this.httpInvokerRequestExecutor == null) { + SimpleHttpInvokerRequestExecutor executor = new SimpleHttpInvokerRequestExecutor(); + executor.setBeanClassLoader(getBeanClassLoader()); + this.httpInvokerRequestExecutor = executor; + } + return this.httpInvokerRequestExecutor; + } + + public void afterPropertiesSet() { + super.afterPropertiesSet(); + + // Eagerly initialize the default HttpInvokerRequestExecutor, if needed. + getHttpInvokerRequestExecutor(); + } + + + public Object invoke(MethodInvocation methodInvocation) throws Throwable { + if (AopUtils.isToStringMethod(methodInvocation.getMethod())) { + return "HTTP invoker proxy for service URL [" + getServiceUrl() + "]"; + } + + RemoteInvocation invocation = createRemoteInvocation(methodInvocation); + RemoteInvocationResult result = null; + try { + result = executeRequest(invocation, methodInvocation); + } + catch (Throwable ex) { + throw convertHttpInvokerAccessException(ex); + } + try { + return recreateRemoteInvocationResult(result); + } + catch (Throwable ex) { + if (result.hasInvocationTargetException()) { + throw ex; + } + else { + throw new RemoteInvocationFailureException("Invocation of method [" + methodInvocation.getMethod() + + "] failed in HTTP invoker remote service at [" + getServiceUrl() + "]", ex); + } + } + } + + /** + * Execute the given remote invocation via the HttpInvokerRequestExecutor. + *

This implementation delegates to {@link #executeRequest(RemoteInvocation)}. + * Can be overridden to react to the specific original MethodInvocation. + * @param invocation the RemoteInvocation to execute + * @param originalInvocation the original MethodInvocation (can e.g. be cast + * to the ProxyMethodInvocation interface for accessing user attributes) + * @return the RemoteInvocationResult object + * @throws Exception in case of errors + */ + protected RemoteInvocationResult executeRequest( + RemoteInvocation invocation, MethodInvocation originalInvocation) throws Exception { + + return executeRequest(invocation); + } + + /** + * Execute the given remote invocation via the HttpInvokerRequestExecutor. + *

Can be overridden in subclasses to pass a different configuration object + * to the executor. Alternatively, add further configuration properties in a + * subclass of this accessor: By default, the accessor passed itself as + * configuration object to the executor. + * @param invocation the RemoteInvocation to execute + * @return the RemoteInvocationResult object + * @throws IOException if thrown by I/O operations + * @throws ClassNotFoundException if thrown during deserialization + * @throws Exception in case of general errors + * @see #getHttpInvokerRequestExecutor + * @see HttpInvokerClientConfiguration + */ + protected RemoteInvocationResult executeRequest(RemoteInvocation invocation) throws Exception { + return getHttpInvokerRequestExecutor().executeRequest(this, invocation); + } + + /** + * Convert the given HTTP invoker access exception to an appropriate + * Spring RemoteAccessException. + * @param ex the exception to convert + * @return the RemoteAccessException to throw + */ + protected RemoteAccessException convertHttpInvokerAccessException(Throwable ex) { + if (ex instanceof ConnectException) { + throw new RemoteConnectFailureException( + "Could not connect to HTTP invoker remote service at [" + getServiceUrl() + "]", ex); + } + else if (ex instanceof ClassNotFoundException || ex instanceof NoClassDefFoundError || + ex instanceof InvalidClassException) { + throw new RemoteAccessException( + "Could not deserialize result from HTTP invoker remote service [" + getServiceUrl() + "]", ex); + } + else { + throw new RemoteAccessException( + "Could not access HTTP invoker remote service at [" + getServiceUrl() + "]", ex); + } + } + +} Index: 3rdParty_sources/spring/org/springframework/remoting/httpinvoker/HttpInvokerProxyFactoryBean.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/remoting/httpinvoker/HttpInvokerProxyFactoryBean.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/remoting/httpinvoker/HttpInvokerProxyFactoryBean.java 17 Aug 2012 15:16:04 -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.remoting.httpinvoker; + +import org.springframework.aop.framework.ProxyFactory; +import org.springframework.beans.factory.FactoryBean; + +/** + * FactoryBean for HTTP invoker proxies. Exposes the proxied service for + * use as a bean reference, using the specified service interface. + * + *

The service URL must be an HTTP URL exposing an HTTP invoker service. + * Optionally, a codebase URL can be specified for on-demand dynamic code download + * from a remote location. For details, see HttpInvokerClientInterceptor docs. + * + *

Serializes remote invocation objects and deserializes remote invocation + * result objects. Uses Java serialization just like RMI, but provides the + * same ease of setup as Caucho's HTTP-based Hessian and Burlap protocols. + * + *

HTTP invoker is the recommended protocol for Java-to-Java remoting. + * It is more powerful and more extensible than Hessian and Burlap, at the + * expense of being tied to Java. Nevertheless, it is as easy to set up as + * Hessian and Burlap, which is its main advantage compared to RMI. + * + * @author Juergen Hoeller + * @since 1.1 + * @see #setServiceInterface + * @see #setServiceUrl + * @see #setCodebaseUrl + * @see HttpInvokerClientInterceptor + * @see HttpInvokerServiceExporter + * @see org.springframework.remoting.rmi.RmiProxyFactoryBean + * @see org.springframework.remoting.caucho.HessianProxyFactoryBean + * @see org.springframework.remoting.caucho.BurlapProxyFactoryBean + */ +public class HttpInvokerProxyFactoryBean extends HttpInvokerClientInterceptor + implements FactoryBean { + + private Object serviceProxy; + + + public void afterPropertiesSet() { + super.afterPropertiesSet(); + if (getServiceInterface() == null) { + throw new IllegalArgumentException("Property 'serviceInterface' is required"); + } + this.serviceProxy = new ProxyFactory(getServiceInterface(), this).getProxy(getBeanClassLoader()); + } + + + public Object getObject() { + return this.serviceProxy; + } + + public Class getObjectType() { + return getServiceInterface(); + } + + public boolean isSingleton() { + return true; + } + +} Index: 3rdParty_sources/spring/org/springframework/remoting/httpinvoker/HttpInvokerRequestExecutor.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/remoting/httpinvoker/HttpInvokerRequestExecutor.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/remoting/httpinvoker/HttpInvokerRequestExecutor.java 17 Aug 2012 15:16:04 -0000 1.1 @@ -0,0 +1,59 @@ +/* + * 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.remoting.httpinvoker; + +import java.io.IOException; + +import org.springframework.remoting.support.RemoteInvocation; +import org.springframework.remoting.support.RemoteInvocationResult; + +/** + * Strategy interface for actual execution of an HTTP invoker request. + * Used by HttpInvokerClientInterceptor and its subclass + * HttpInvokerProxyFactoryBean. + * + *

Two implementations are provided out of the box: + *

    + *
  • SimpleHttpInvokerRequestExecutor: + * Uses J2SE facilities to execute POST requests, without support + * for HTTP authentication or advanced configuration options. + *
  • CommonsHttpInvokerRequestExecutor: + * Uses Jakarta's Commons HttpClient to execute POST requests, + * allowing to use a preconfigured HttpClient instance + * (potentially with authentication, HTTP connection pooling, etc). + *
+ * + * @author Juergen Hoeller + * @since 1.1 + * @see HttpInvokerClientInterceptor#setHttpInvokerRequestExecutor + */ +public interface HttpInvokerRequestExecutor { + + /** + * Execute a request to send the given remote invocation. + * @param config the HTTP invoker configuration that specifies the + * target service + * @param invocation the RemoteInvocation to execute + * @return the RemoteInvocationResult object + * @throws IOException if thrown by I/O operations + * @throws ClassNotFoundException if thrown during deserialization + * @throws Exception in case of general errors + */ + RemoteInvocationResult executeRequest(HttpInvokerClientConfiguration config, RemoteInvocation invocation) + throws Exception; + +} Index: 3rdParty_sources/spring/org/springframework/remoting/httpinvoker/HttpInvokerServiceExporter.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/remoting/httpinvoker/HttpInvokerServiceExporter.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/remoting/httpinvoker/HttpInvokerServiceExporter.java 17 Aug 2012 15:16:05 -0000 1.1 @@ -0,0 +1,199 @@ +/* + * 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.remoting.httpinvoker; + +import java.io.IOException; +import java.io.InputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.OutputStream; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.springframework.remoting.rmi.RemoteInvocationSerializingExporter; +import org.springframework.remoting.support.RemoteInvocation; +import org.springframework.remoting.support.RemoteInvocationResult; +import org.springframework.web.HttpRequestHandler; +import org.springframework.web.util.NestedServletException; + +/** + * Servlet-API-based HTTP request handler that exports the specified service bean + * as HTTP invoker service endpoint, accessible via an HTTP invoker proxy. + * + *

Note: Spring also provides an alternative version of this exporter, + * for Sun's JRE 1.6 HTTP server: {@link SimpleHttpInvokerServiceExporter}. + * + *

Deserializes remote invocation objects and serializes remote invocation + * result objects. Uses Java serialization just like RMI, but provides the + * same ease of setup as Caucho's HTTP-based Hessian and Burlap protocols. + * + *

HTTP invoker is the recommended protocol for Java-to-Java remoting. + * It is more powerful and more extensible than Hessian and Burlap, at the + * expense of being tied to Java. Nevertheless, it is as easy to set up as + * Hessian and Burlap, which is its main advantage compared to RMI. + * + * @author Juergen Hoeller + * @since 1.1 + * @see HttpInvokerClientInterceptor + * @see HttpInvokerProxyFactoryBean + * @see org.springframework.remoting.rmi.RmiServiceExporter + * @see org.springframework.remoting.caucho.HessianServiceExporter + * @see org.springframework.remoting.caucho.BurlapServiceExporter + */ +public class HttpInvokerServiceExporter extends RemoteInvocationSerializingExporter + implements HttpRequestHandler { + + /** + * Reads a remote invocation from the request, executes it, + * and writes the remote invocation result to the response. + * @see #readRemoteInvocation(HttpServletRequest) + * @see #invokeAndCreateResult(org.springframework.remoting.support.RemoteInvocation, Object) + * @see #writeRemoteInvocationResult(HttpServletRequest, HttpServletResponse, RemoteInvocationResult) + */ + public void handleRequest(HttpServletRequest request, HttpServletResponse response) + throws ServletException, IOException { + + try { + RemoteInvocation invocation = readRemoteInvocation(request); + RemoteInvocationResult result = invokeAndCreateResult(invocation, getProxy()); + writeRemoteInvocationResult(request, response, result); + } + catch (ClassNotFoundException ex) { + throw new NestedServletException("Class not found during deserialization", ex); + } + } + + /** + * Read a RemoteInvocation from the given HTTP request. + *

Delegates to + * {@link #readRemoteInvocation(javax.servlet.http.HttpServletRequest, java.io.InputStream)} + * with the + * {@link javax.servlet.ServletRequest#getInputStream() servlet request's input stream}. + * @param request current HTTP request + * @return the RemoteInvocation object + * @throws IOException in case of I/O failure + * @throws ClassNotFoundException if thrown by deserialization + */ + protected RemoteInvocation readRemoteInvocation(HttpServletRequest request) + throws IOException, ClassNotFoundException { + + return readRemoteInvocation(request, request.getInputStream()); + } + + /** + * Deserialize a RemoteInvocation object from the given InputStream. + *

Gives {@link #decorateInputStream} a chance to decorate the stream + * first (for example, for custom encryption or compression). Creates a + * {@link org.springframework.remoting.rmi.CodebaseAwareObjectInputStream} + * and calls {@link #doReadRemoteInvocation} to actually read the object. + *

Can be overridden for custom serialization of the invocation. + * @param request current HTTP request + * @param is the InputStream to read from + * @return the RemoteInvocation object + * @throws IOException in case of I/O failure + * @throws ClassNotFoundException if thrown during deserialization + */ + protected RemoteInvocation readRemoteInvocation(HttpServletRequest request, InputStream is) + throws IOException, ClassNotFoundException { + + ObjectInputStream ois = createObjectInputStream(decorateInputStream(request, is)); + try { + return doReadRemoteInvocation(ois); + } + finally { + ois.close(); + } + } + + /** + * Return the InputStream to use for reading remote invocations, + * potentially decorating the given original InputStream. + *

The default implementation returns the given stream as-is. + * Can be overridden, for example, for custom encryption or compression. + * @param request current HTTP request + * @param is the original InputStream + * @return the potentially decorated InputStream + * @throws IOException in case of I/O failure + */ + protected InputStream decorateInputStream(HttpServletRequest request, InputStream is) throws IOException { + return is; + } + + /** + * Write the given RemoteInvocationResult to the given HTTP response. + * @param request current HTTP request + * @param response current HTTP response + * @param result the RemoteInvocationResult object + * @throws IOException in case of I/O failure + */ + protected void writeRemoteInvocationResult( + HttpServletRequest request, HttpServletResponse response, RemoteInvocationResult result) + throws IOException { + + response.setContentType(getContentType()); + writeRemoteInvocationResult(request, response, result, response.getOutputStream()); + } + + /** + * Serialize the given RemoteInvocation to the given OutputStream. + *

The default implementation gives {@link #decorateOutputStream} a chance + * to decorate the stream first (for example, for custom encryption or compression). + * Creates an {@link java.io.ObjectOutputStream} for the final stream and calls + * {@link #doWriteRemoteInvocationResult} to actually write the object. + *

Can be overridden for custom serialization of the invocation. + * @param request current HTTP request + * @param response current HTTP response + * @param result the RemoteInvocationResult object + * @param os the OutputStream to write to + * @throws IOException in case of I/O failure + * @see #decorateOutputStream + * @see #doWriteRemoteInvocationResult + */ + protected void writeRemoteInvocationResult( + HttpServletRequest request, HttpServletResponse response, RemoteInvocationResult result, OutputStream os) + throws IOException { + + ObjectOutputStream oos = createObjectOutputStream(decorateOutputStream(request, response, os)); + try { + doWriteRemoteInvocationResult(result, oos); + oos.flush(); + } + finally { + oos.close(); + } + } + + /** + * Return the OutputStream to use for writing remote invocation results, + * potentially decorating the given original OutputStream. + *

The default implementation returns the given stream as-is. + * Can be overridden, for example, for custom encryption or compression. + * @param request current HTTP request + * @param response current HTTP response + * @param os the original OutputStream + * @return the potentially decorated OutputStream + * @throws IOException in case of I/O failure + */ + protected OutputStream decorateOutputStream( + HttpServletRequest request, HttpServletResponse response, OutputStream os) throws IOException { + + return os; + } + +} Index: 3rdParty_sources/spring/org/springframework/remoting/httpinvoker/SimpleHttpInvokerRequestExecutor.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/remoting/httpinvoker/SimpleHttpInvokerRequestExecutor.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/remoting/httpinvoker/SimpleHttpInvokerRequestExecutor.java 17 Aug 2012 15:16:05 -0000 1.1 @@ -0,0 +1,192 @@ +/* + * 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.remoting.httpinvoker; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.HttpURLConnection; +import java.net.URL; +import java.net.URLConnection; +import java.util.zip.GZIPInputStream; + +import org.springframework.context.i18n.LocaleContext; +import org.springframework.context.i18n.LocaleContextHolder; +import org.springframework.remoting.support.RemoteInvocationResult; +import org.springframework.util.StringUtils; + +/** + * HttpInvokerRequestExecutor implementation that uses standard J2SE facilities + * to execute POST requests, without support for HTTP authentication or + * advanced configuration options. + * + *

Designed for easy subclassing, customizing specific template methods. + * However, consider CommonsHttpInvokerRequestExecutor for more sophisticated + * needs: The J2SE HttpURLConnection is rather limited in its capabilities. + * + * @author Juergen Hoeller + * @since 1.1 + * @see CommonsHttpInvokerRequestExecutor + * @see java.net.HttpURLConnection + */ +public class SimpleHttpInvokerRequestExecutor extends AbstractHttpInvokerRequestExecutor { + + /** + * Execute the given request through a standard J2SE HttpURLConnection. + *

This method implements the basic processing workflow: + * The actual work happens in this class's template methods. + * @see #openConnection + * @see #prepareConnection + * @see #writeRequestBody + * @see #validateResponse + * @see #readResponseBody + */ + protected RemoteInvocationResult doExecuteRequest( + HttpInvokerClientConfiguration config, ByteArrayOutputStream baos) + throws IOException, ClassNotFoundException { + + HttpURLConnection con = openConnection(config); + prepareConnection(con, baos.size()); + writeRequestBody(config, con, baos); + validateResponse(config, con); + InputStream responseBody = readResponseBody(config, con); + + return readRemoteInvocationResult(responseBody, config.getCodebaseUrl()); + } + + /** + * Open an HttpURLConnection for the given remote invocation request. + * @param config the HTTP invoker configuration that specifies the + * target service + * @return the HttpURLConnection for the given request + * @throws IOException if thrown by I/O methods + * @see java.net.URL#openConnection() + */ + protected HttpURLConnection openConnection(HttpInvokerClientConfiguration config) throws IOException { + URLConnection con = new URL(config.getServiceUrl()).openConnection(); + if (!(con instanceof HttpURLConnection)) { + throw new IOException("Service URL [" + config.getServiceUrl() + "] is not an HTTP URL"); + } + return (HttpURLConnection) con; + } + + /** + * Prepare the given HTTP connection. + *

The default implementation specifies POST as method, + * "application/x-java-serialized-object" as "Content-Type" header, + * and the given content length as "Content-Length" header. + * @param con the HTTP connection to prepare + * @param contentLength the length of the content to send + * @throws IOException if thrown by HttpURLConnection methods + * @see java.net.HttpURLConnection#setRequestMethod + * @see java.net.HttpURLConnection#setRequestProperty + */ + protected void prepareConnection(HttpURLConnection con, int contentLength) throws IOException { + con.setDoOutput(true); + con.setRequestMethod(HTTP_METHOD_POST); + con.setRequestProperty(HTTP_HEADER_CONTENT_TYPE, getContentType()); + con.setRequestProperty(HTTP_HEADER_CONTENT_LENGTH, Integer.toString(contentLength)); + LocaleContext locale = LocaleContextHolder.getLocaleContext(); + if (locale != null) { + con.setRequestProperty(HTTP_HEADER_ACCEPT_LANGUAGE, StringUtils.toLanguageTag(locale.getLocale())); + } + if (isAcceptGzipEncoding()) { + con.setRequestProperty(HTTP_HEADER_ACCEPT_ENCODING, ENCODING_GZIP); + } + } + + /** + * Set the given serialized remote invocation as request body. + *

The default implementation simply write the serialized invocation to the + * HttpURLConnection's OutputStream. This can be overridden, for example, to write + * a specific encoding and potentially set appropriate HTTP request headers. + * @param config the HTTP invoker configuration that specifies the target service + * @param con the HttpURLConnection to write the request body to + * @param baos the ByteArrayOutputStream that contains the serialized + * RemoteInvocation object + * @throws IOException if thrown by I/O methods + * @see java.net.HttpURLConnection#getOutputStream() + * @see java.net.HttpURLConnection#setRequestProperty + */ + protected void writeRequestBody( + HttpInvokerClientConfiguration config, HttpURLConnection con, ByteArrayOutputStream baos) + throws IOException { + + baos.writeTo(con.getOutputStream()); + } + + /** + * Validate the given response as contained in the HttpURLConnection object, + * throwing an exception if it does not correspond to a successful HTTP response. + *

Default implementation rejects any HTTP status code beyond 2xx, to avoid + * parsing the response body and trying to deserialize from a corrupted stream. + * @param config the HTTP invoker configuration that specifies the target service + * @param con the HttpURLConnection to validate + * @throws IOException if validation failed + * @see java.net.HttpURLConnection#getResponseCode() + */ + protected void validateResponse(HttpInvokerClientConfiguration config, HttpURLConnection con) + throws IOException { + + if (con.getResponseCode() >= 300) { + throw new IOException( + "Did not receive successful HTTP response: status code = " + con.getResponseCode() + + ", status message = [" + con.getResponseMessage() + "]"); + } + } + + /** + * Extract the response body from the given executed remote invocation + * request. + *

The default implementation simply reads the serialized invocation + * from the HttpURLConnection's InputStream. If the response is recognized + * as GZIP response, the InputStream will get wrapped in a GZIPInputStream. + * @param config the HTTP invoker configuration that specifies the target service + * @param con the HttpURLConnection to read the response body from + * @return an InputStream for the response body + * @throws IOException if thrown by I/O methods + * @see #isGzipResponse + * @see java.util.zip.GZIPInputStream + * @see java.net.HttpURLConnection#getInputStream() + * @see java.net.HttpURLConnection#getHeaderField(int) + * @see java.net.HttpURLConnection#getHeaderFieldKey(int) + */ + protected InputStream readResponseBody(HttpInvokerClientConfiguration config, HttpURLConnection con) + throws IOException { + + if (isGzipResponse(con)) { + // GZIP response found - need to unzip. + return new GZIPInputStream(con.getInputStream()); + } + else { + // Plain response found. + return con.getInputStream(); + } + } + + /** + * Determine whether the given response is a GZIP response. + *

Default implementation checks whether the HTTP "Content-Encoding" + * header contains "gzip" (in any casing). + * @param con the HttpURLConnection to check + */ + protected boolean isGzipResponse(HttpURLConnection con) { + String encodingHeader = con.getHeaderField(HTTP_HEADER_CONTENT_ENCODING); + return (encodingHeader != null && encodingHeader.toLowerCase().indexOf(ENCODING_GZIP) != -1); + } + +} Index: 3rdParty_sources/spring/org/springframework/remoting/httpinvoker/SimpleHttpInvokerServiceExporter.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/remoting/httpinvoker/SimpleHttpInvokerServiceExporter.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/remoting/httpinvoker/SimpleHttpInvokerServiceExporter.java 17 Aug 2012 15:16:04 -0000 1.1 @@ -0,0 +1,177 @@ +/* + * 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.remoting.httpinvoker; + +import java.io.IOException; +import java.io.InputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.OutputStream; + +import com.sun.net.httpserver.HttpExchange; +import com.sun.net.httpserver.HttpHandler; + +import org.springframework.remoting.rmi.RemoteInvocationSerializingExporter; +import org.springframework.remoting.support.RemoteInvocation; +import org.springframework.remoting.support.RemoteInvocationResult; + +/** + * HTTP request handler that exports the specified service bean as + * HTTP invoker service endpoint, accessible via an HTTP invoker proxy. + * Designed for Sun's JRE 1.6 HTTP server, implementing the + * {@link com.sun.net.httpserver.HttpHandler} interface. + * + *

Deserializes remote invocation objects and serializes remote invocation + * result objects. Uses Java serialization just like RMI, but provides the + * same ease of setup as Caucho's HTTP-based Hessian and Burlap protocols. + * + *

HTTP invoker is the recommended protocol for Java-to-Java remoting. + * It is more powerful and more extensible than Hessian and Burlap, at the + * expense of being tied to Java. Nevertheless, it is as easy to set up as + * Hessian and Burlap, which is its main advantage compared to RMI. + * + * @author Juergen Hoeller + * @since 2.5.1 + * @see org.springframework.remoting.httpinvoker.HttpInvokerClientInterceptor + * @see org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean + * @see org.springframework.remoting.caucho.SimpleHessianServiceExporter + * @see org.springframework.remoting.caucho.SimpleBurlapServiceExporter + */ +public class SimpleHttpInvokerServiceExporter extends RemoteInvocationSerializingExporter + implements HttpHandler { + + /** + * Reads a remote invocation from the request, executes it, + * and writes the remote invocation result to the response. + * @see #readRemoteInvocation(com.sun.net.httpserver.HttpExchange) + * @see #invokeAndCreateResult(org.springframework.remoting.support.RemoteInvocation, Object) + * @see #writeRemoteInvocationResult(com.sun.net.httpserver.HttpExchange, org.springframework.remoting.support.RemoteInvocationResult) + */ + public void handle(HttpExchange exchange) throws IOException { + try { + RemoteInvocation invocation = readRemoteInvocation(exchange); + RemoteInvocationResult result = invokeAndCreateResult(invocation, getProxy()); + writeRemoteInvocationResult(exchange, result); + exchange.close(); + } + catch (ClassNotFoundException ex) { + throw new IOException("Class not found during deserialization", ex); + } + } + + /** + * Read a RemoteInvocation from the given HTTP request. + *

Delegates to + * {@link #readRemoteInvocation(com.sun.net.httpserver.HttpExchange, java.io.InputStream)} + * with the + * {@link com.sun.net.httpserver.HttpExchange#getRequestBody()} request's input stream}. + * @param exchange current HTTP request/response + * @return the RemoteInvocation object + * @throws java.io.IOException in case of I/O failure + * @throws ClassNotFoundException if thrown by deserialization + */ + protected RemoteInvocation readRemoteInvocation(HttpExchange exchange) + throws IOException, ClassNotFoundException { + + return readRemoteInvocation(exchange, exchange.getRequestBody()); + } + + /** + * Deserialize a RemoteInvocation object from the given InputStream. + *

Gives {@link #decorateInputStream} a chance to decorate the stream + * first (for example, for custom encryption or compression). Creates a + * {@link org.springframework.remoting.rmi.CodebaseAwareObjectInputStream} + * and calls {@link #doReadRemoteInvocation} to actually read the object. + *

Can be overridden for custom serialization of the invocation. + * @param exchange current HTTP request/response + * @param is the InputStream to read from + * @return the RemoteInvocation object + * @throws java.io.IOException in case of I/O failure + * @throws ClassNotFoundException if thrown during deserialization + */ + protected RemoteInvocation readRemoteInvocation(HttpExchange exchange, InputStream is) + throws IOException, ClassNotFoundException { + + ObjectInputStream ois = createObjectInputStream(decorateInputStream(exchange, is)); + return doReadRemoteInvocation(ois); + } + + /** + * Return the InputStream to use for reading remote invocations, + * potentially decorating the given original InputStream. + *

The default implementation returns the given stream as-is. + * Can be overridden, for example, for custom encryption or compression. + * @param exchange current HTTP request/response + * @param is the original InputStream + * @return the potentially decorated InputStream + * @throws java.io.IOException in case of I/O failure + */ + protected InputStream decorateInputStream(HttpExchange exchange, InputStream is) throws IOException { + return is; + } + + /** + * Write the given RemoteInvocationResult to the given HTTP response. + * @param exchange current HTTP request/response + * @param result the RemoteInvocationResult object + * @throws java.io.IOException in case of I/O failure + */ + protected void writeRemoteInvocationResult(HttpExchange exchange, RemoteInvocationResult result) + throws IOException { + + exchange.getResponseHeaders().set("Content-Type", getContentType()); + exchange.sendResponseHeaders(200, 0); + writeRemoteInvocationResult(exchange, result, exchange.getResponseBody()); + } + + /** + * Serialize the given RemoteInvocation to the given OutputStream. + *

The default implementation gives {@link #decorateOutputStream} a chance + * to decorate the stream first (for example, for custom encryption or compression). + * Creates an {@link java.io.ObjectOutputStream} for the final stream and calls + * {@link #doWriteRemoteInvocationResult} to actually write the object. + *

Can be overridden for custom serialization of the invocation. + * @param exchange current HTTP request/response + * @param result the RemoteInvocationResult object + * @param os the OutputStream to write to + * @throws java.io.IOException in case of I/O failure + * @see #decorateOutputStream + * @see #doWriteRemoteInvocationResult + */ + protected void writeRemoteInvocationResult( + HttpExchange exchange, RemoteInvocationResult result, OutputStream os) throws IOException { + + ObjectOutputStream oos = createObjectOutputStream(decorateOutputStream(exchange, os)); + doWriteRemoteInvocationResult(result, oos); + oos.flush(); + } + + /** + * Return the OutputStream to use for writing remote invocation results, + * potentially decorating the given original OutputStream. + *

The default implementation returns the given stream as-is. + * Can be overridden, for example, for custom encryption or compression. + * @param exchange current HTTP request/response + * @param os the original OutputStream + * @return the potentially decorated OutputStream + * @throws java.io.IOException in case of I/O failure + */ + protected OutputStream decorateOutputStream(HttpExchange exchange, OutputStream os) throws IOException { + return os; + } + +} Index: 3rdParty_sources/spring/org/springframework/remoting/httpinvoker/package.html =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/remoting/httpinvoker/package.html,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/remoting/httpinvoker/package.html 17 Aug 2012 15:16:05 -0000 1.1 @@ -0,0 +1,14 @@ + + + +Remoting classes for transparent Java-to-Java remoting via HTTP invokers. +Uses Java serialization just like RMI, but provides the same ease of setup +as Caucho's HTTP-based Hessian and Burlap protocols. + +

HTTP invoker is the recommended protocol for Java-to-Java remoting. +It is more powerful and more extensible than Hessian and Burlap, at the +expense of being tied to Java. Neverthelesss, it is as easy to set up as +Hessian and Burlap, which is its main advantage compared to RMI. + + + Index: 3rdParty_sources/spring/org/springframework/remoting/jaxrpc/JaxRpcPortClientInterceptor.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/remoting/jaxrpc/JaxRpcPortClientInterceptor.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/remoting/jaxrpc/JaxRpcPortClientInterceptor.java 17 Aug 2012 15:16:06 -0000 1.1 @@ -0,0 +1,757 @@ +/* + * 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.remoting.jaxrpc; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.rmi.Remote; +import java.rmi.RemoteException; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.Properties; + +import javax.xml.namespace.QName; +import javax.xml.rpc.Call; +import javax.xml.rpc.JAXRPCException; +import javax.xml.rpc.Service; +import javax.xml.rpc.ServiceException; +import javax.xml.rpc.Stub; +import javax.xml.rpc.soap.SOAPFaultException; + +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.remoting.RemoteLookupFailureException; +import org.springframework.remoting.RemoteProxyFailureException; +import org.springframework.remoting.rmi.RmiClientInterceptorUtils; +import org.springframework.util.CollectionUtils; +import org.springframework.util.ReflectionUtils; + +/** + * {@link org.aopalliance.intercept.MethodInterceptor} for accessing a specific port + * of a JAX-RPC service. Uses either {@link LocalJaxRpcServiceFactory}'s facilities + * underneath or takes an explicit reference to an existing JAX-RPC Service instance + * (e.g. obtained via a {@link org.springframework.jndi.JndiObjectFactoryBean}). + * + *

Allows to set JAX-RPC's standard stub properties directly, via the + * "username", "password", "endpointAddress" and "maintainSession" properties. + * For typical usage, it is not necessary to specify those. + * + *

In standard JAX-RPC style, this invoker is used with an RMI service interface. + * Alternatively, this invoker can also proxy a JAX-RPC service with a matching + * non-RMI business interface, that is, an interface that declares the service methods + * without RemoteExceptions. In the latter case, RemoteExceptions thrown by JAX-RPC + * will automatically get converted to Spring's unchecked RemoteAccessException. + * + *

Setting "serviceInterface" is usually sufficient: The invoker will automatically + * use JAX-RPC "dynamic invocations" via the Call API in this case, no matter whether + * the specified interface is an RMI or non-RMI interface. Alternatively, a corresponding + * JAX-RPC port interface can be specified as "portInterface", which will turn this + * invoker into "static invocation" mode (operating on a standard JAX-RPC port stub). + * + * @author Juergen Hoeller + * @since 15.12.2003 + * @see #setPortName + * @see #setServiceInterface + * @see #setPortInterface + * @see javax.xml.rpc.Service#createCall + * @see javax.xml.rpc.Service#getPort + * @see org.springframework.remoting.RemoteAccessException + * @see org.springframework.jndi.JndiObjectFactoryBean + */ +public class JaxRpcPortClientInterceptor extends LocalJaxRpcServiceFactory + implements MethodInterceptor, InitializingBean { + + private Service jaxRpcService; + + private Service serviceToUse; + + private String portName; + + private String username; + + private String password; + + private String endpointAddress; + + private boolean maintainSession; + + /** Map of custom properties, keyed by property name (String) */ + private final Map customPropertyMap = new HashMap(); + + private Class serviceInterface; + + private Class portInterface; + + private boolean lookupServiceOnStartup = true; + + private boolean refreshServiceAfterConnectFailure = false; + + private QName portQName; + + private Remote portStub; + + private final Object preparationMonitor = new Object(); + + + /** + * Set a reference to an existing JAX-RPC Service instance, + * for example obtained via {@link org.springframework.jndi.JndiObjectFactoryBean}. + * If not set, {@link LocalJaxRpcServiceFactory}'s properties have to be specified. + * @see #setServiceFactoryClass + * @see #setWsdlDocumentUrl + * @see #setNamespaceUri + * @see #setServiceName + * @see org.springframework.jndi.JndiObjectFactoryBean + */ + public void setJaxRpcService(Service jaxRpcService) { + this.jaxRpcService = jaxRpcService; + } + + /** + * Return a reference to an existing JAX-RPC Service instance, if any. + */ + public Service getJaxRpcService() { + return this.jaxRpcService; + } + + /** + * Set the name of the port. + * Corresponds to the "wsdl:port" name. + */ + public void setPortName(String portName) { + this.portName = portName; + } + + /** + * Return the name of the port. + */ + public String getPortName() { + return this.portName; + } + + /** + * Set the username to specify on the stub or call. + * @see javax.xml.rpc.Stub#USERNAME_PROPERTY + * @see javax.xml.rpc.Call#USERNAME_PROPERTY + */ + public void setUsername(String username) { + this.username = username; + } + + /** + * Return the username to specify on the stub or call. + */ + public String getUsername() { + return this.username; + } + + /** + * Set the password to specify on the stub or call. + * @see javax.xml.rpc.Stub#PASSWORD_PROPERTY + * @see javax.xml.rpc.Call#PASSWORD_PROPERTY + */ + public void setPassword(String password) { + this.password = password; + } + + /** + * Return the password to specify on the stub or call. + */ + public String getPassword() { + return this.password; + } + + /** + * Set the endpoint address to specify on the stub or call. + * @see javax.xml.rpc.Stub#ENDPOINT_ADDRESS_PROPERTY + * @see javax.xml.rpc.Call#setTargetEndpointAddress + */ + public void setEndpointAddress(String endpointAddress) { + this.endpointAddress = endpointAddress; + } + + /** + * Return the endpoint address to specify on the stub or call. + */ + public String getEndpointAddress() { + return this.endpointAddress; + } + + /** + * Set the maintain session flag to specify on the stub or call. + * @see javax.xml.rpc.Stub#SESSION_MAINTAIN_PROPERTY + * @see javax.xml.rpc.Call#SESSION_MAINTAIN_PROPERTY + */ + public void setMaintainSession(boolean maintainSession) { + this.maintainSession = maintainSession; + } + + /** + * Return the maintain session flag to specify on the stub or call. + */ + public boolean isMaintainSession() { + return this.maintainSession; + } + + /** + * Set custom properties to be set on the stub or call. + *

Can be populated with a String "value" (parsed via PropertiesEditor) + * or a "props" element in XML bean definitions. + * @see javax.xml.rpc.Stub#_setProperty + * @see javax.xml.rpc.Call#setProperty + */ + public void setCustomProperties(Properties customProperties) { + CollectionUtils.mergePropertiesIntoMap(customProperties, this.customPropertyMap); + } + + /** + * Set custom properties to be set on the stub or call. + *

Can be populated with a "map" or "props" element in XML bean definitions. + * @see javax.xml.rpc.Stub#_setProperty + * @see javax.xml.rpc.Call#setProperty + */ + public void setCustomPropertyMap(Map customProperties) { + if (customProperties != null) { + Iterator it = customProperties.entrySet().iterator(); + while (it.hasNext()) { + Map.Entry entry = (Map.Entry) it.next(); + if (!(entry.getKey() instanceof String)) { + throw new IllegalArgumentException( + "Illegal property key [" + entry.getKey() + "]: only Strings allowed"); + } + addCustomProperty((String) entry.getKey(), entry.getValue()); + } + } + } + + /** + * Allow Map access to the custom properties to be set on the stub + * or call, with the option to add or override specific entries. + *

Useful for specifying entries directly, for example via + * "customPropertyMap[myKey]". This is particularly useful for + * adding or overriding entries in child bean definitions. + */ + public Map getCustomPropertyMap() { + return this.customPropertyMap; + } + + /** + * Add a custom property to this JAX-RPC Stub/Call. + * @param name the name of the attribute to expose + * @param value the attribute value to expose + * @see javax.xml.rpc.Stub#_setProperty + * @see javax.xml.rpc.Call#setProperty + */ + public void addCustomProperty(String name, Object value) { + this.customPropertyMap.put(name, value); + } + + /** + * Set the interface of the service that this factory should create a proxy for. + * This will typically be a non-RMI business interface, although you can also + * use an RMI port interface as recommended by JAX-RPC here. + *

Calls on the specified service interface will either be translated to the + * underlying RMI port interface (in case of a "portInterface" being specified) + * or to dynamic calls (using the JAX-RPC Dynamic Invocation Interface). + *

The dynamic call mechanism has the advantage that you don't need to + * maintain an RMI port interface in addition to an existing non-RMI business + * interface. In terms of configuration, specifying the business interface + * as "serviceInterface" will be enough; this interceptor will automatically + * use dynamic calls in such a scenario. + * @see javax.xml.rpc.Service#createCall + * @see #setPortInterface + */ + public void setServiceInterface(Class serviceInterface) { + if (serviceInterface != null && !serviceInterface.isInterface()) { + throw new IllegalArgumentException("'serviceInterface' must be an interface"); + } + this.serviceInterface = serviceInterface; + } + + /** + * Return the interface of the service that this factory should create a proxy for. + */ + public Class getServiceInterface() { + return this.serviceInterface; + } + + /** + * Set the JAX-RPC port interface to use. Only needs to be set if a JAX-RPC + * port stub should be used instead of the dynamic call mechanism. + * See the javadoc of the "serviceInterface" property for more details. + *

The interface must be suitable for a JAX-RPC port, that is, it must be + * an RMI service interface (that extends java.rmi.Remote). + *

NOTE: Check whether your JAX-RPC provider returns thread-safe + * port stubs. If not, use the dynamic call mechanism instead, which will + * always be thread-safe. In particular, do not use JAX-RPC port stubs + * with Apache Axis, whose port stubs are known to be non-thread-safe. + * @see javax.xml.rpc.Service#getPort + * @see java.rmi.Remote + * @see #setServiceInterface + */ + public void setPortInterface(Class portInterface) { + if (portInterface != null && + (!portInterface.isInterface() || !Remote.class.isAssignableFrom(portInterface))) { + throw new IllegalArgumentException( + "'portInterface' must be an interface derived from [java.rmi.Remote]"); + } + this.portInterface = portInterface; + } + + /** + * Return the JAX-RPC port interface to use. + */ + public Class getPortInterface() { + return this.portInterface; + } + + /** + * Set whether to look up the JAX-RPC service on startup. + *

Default is "true". Turn this flag off to allow for late start + * of the target server. In this case, the JAX-RPC service will be + * lazily fetched on first access. + */ + public void setLookupServiceOnStartup(boolean lookupServiceOnStartup) { + this.lookupServiceOnStartup = lookupServiceOnStartup; + } + + /** + * Set whether to refresh the JAX-RPC service on connect failure, + * that is, whenever a JAX-RPC invocation throws a RemoteException. + *

Default is "false", keeping a reference to the JAX-RPC service + * in any case, retrying the next invocation on the same service + * even in case of failure. Turn this flag on to reinitialize the + * entire service in case of connect failures. + */ + public void setRefreshServiceAfterConnectFailure(boolean refreshServiceAfterConnectFailure) { + this.refreshServiceAfterConnectFailure = refreshServiceAfterConnectFailure; + } + + + /** + * Prepares the JAX-RPC service and port if the "lookupServiceOnStartup" + * is turned on (which it is by default). + */ + public void afterPropertiesSet() { + if (this.lookupServiceOnStartup) { + prepare(); + } + } + + /** + * Create and initialize the JAX-RPC service for the specified port. + *

Prepares a JAX-RPC stub if possible (if an RMI interface is available); + * falls back to JAX-RPC dynamic calls else. Using dynamic calls can be enforced + * through overriding {@link #alwaysUseJaxRpcCall} to return true. + *

{@link #postProcessJaxRpcService} and {@link #postProcessPortStub} + * hooks are available for customization in subclasses. When using dynamic calls, + * each can be post-processed via {@link #postProcessJaxRpcCall}. + * @throws RemoteLookupFailureException if service initialization or port stub creation failed + */ + public void prepare() throws RemoteLookupFailureException { + if (getPortName() == null) { + throw new IllegalArgumentException("Property 'portName' is required"); + } + + synchronized (this.preparationMonitor) { + this.serviceToUse = null; + + // Cache the QName for the port. + this.portQName = getQName(getPortName()); + + try { + Service service = getJaxRpcService(); + if (service == null) { + service = createJaxRpcService(); + } + else { + postProcessJaxRpcService(service); + } + + Class portInterface = getPortInterface(); + if (portInterface != null && !alwaysUseJaxRpcCall()) { + // JAX-RPC-compliant port interface -> using JAX-RPC stub for port. + + if (logger.isDebugEnabled()) { + logger.debug("Creating JAX-RPC proxy for JAX-RPC port [" + this.portQName + + "], using port interface [" + portInterface.getName() + "]"); + } + Remote remoteObj = service.getPort(this.portQName, portInterface); + + if (logger.isDebugEnabled()) { + Class serviceInterface = getServiceInterface(); + if (serviceInterface != null) { + boolean isImpl = serviceInterface.isInstance(remoteObj); + logger.debug("Using service interface [" + serviceInterface.getName() + "] for JAX-RPC port [" + + this.portQName + "] - " + (!isImpl ? "not" : "") + " directly implemented"); + } + } + + if (!(remoteObj instanceof Stub)) { + throw new RemoteLookupFailureException("Port stub of class [" + remoteObj.getClass().getName() + + "] is not a valid JAX-RPC stub: it does not implement interface [javax.xml.rpc.Stub]"); + } + Stub stub = (Stub) remoteObj; + + // Apply properties to JAX-RPC stub. + preparePortStub(stub); + + // Allow for custom post-processing in subclasses. + postProcessPortStub(stub); + + this.portStub = remoteObj; + } + + else { + // No JAX-RPC-compliant port interface -> using JAX-RPC dynamic calls. + if (logger.isDebugEnabled()) { + logger.debug("Using JAX-RPC dynamic calls for JAX-RPC port [" + this.portQName + "]"); + } + } + + this.serviceToUse = service; + } + catch (ServiceException ex) { + throw new RemoteLookupFailureException( + "Failed to initialize service for JAX-RPC port [" + this.portQName + "]", ex); + } + } + } + + /** + * Return whether to always use JAX-RPC dynamic calls. + * Called by afterPropertiesSet. + *

Default is "false"; if an RMI interface is specified as "portInterface" + * or "serviceInterface", it will be used to create a JAX-RPC port stub. + *

Can be overridden to enforce the use of the JAX-RPC Call API, + * for example if there is a need to customize at the Call level. + * This just necessary if you you want to use an RMI interface as + * "serviceInterface", though; in case of only a non-RMI interface being + * available, this interceptor will fall back to the Call API anyway. + * @see #postProcessJaxRpcCall + */ + protected boolean alwaysUseJaxRpcCall() { + return false; + } + + /** + * Reset the prepared service of this interceptor, + * allowing for reinitialization on next access. + */ + protected void reset() { + synchronized (this.preparationMonitor) { + this.serviceToUse = null; + } + } + + /** + * Return whether this client interceptor has already been prepared, + * i.e. has already looked up the JAX-RPC service and port. + */ + protected boolean isPrepared() { + synchronized (this.preparationMonitor) { + return (this.serviceToUse != null); + } + } + + /** + * Return the prepared QName for the port. + * @see #setPortName + * @see #getQName + */ + protected final QName getPortQName() { + return this.portQName; + } + + + /** + * Prepare the given JAX-RPC port stub, applying properties to it. + * Called by {@link #prepare}. + *

Just applied when actually creating a JAX-RPC port stub, in case of a + * compliant port interface. Else, JAX-RPC dynamic calls will be used. + * @param stub the current JAX-RPC port stub + * @see #setUsername + * @see #setPassword + * @see #setEndpointAddress + * @see #setMaintainSession + * @see #setCustomProperties + * @see #setPortInterface + * @see #prepareJaxRpcCall + */ + protected void preparePortStub(Stub stub) { + String username = getUsername(); + if (username != null) { + stub._setProperty(Stub.USERNAME_PROPERTY, username); + } + String password = getPassword(); + if (password != null) { + stub._setProperty(Stub.PASSWORD_PROPERTY, password); + } + String endpointAddress = getEndpointAddress(); + if (endpointAddress != null) { + stub._setProperty(Stub.ENDPOINT_ADDRESS_PROPERTY, endpointAddress); + } + if (isMaintainSession()) { + stub._setProperty(Stub.SESSION_MAINTAIN_PROPERTY, Boolean.TRUE); + } + if (this.customPropertyMap != null) { + for (Iterator it = this.customPropertyMap.keySet().iterator(); it.hasNext();) { + String key = (String) it.next(); + stub._setProperty(key, this.customPropertyMap.get(key)); + } + } + } + + /** + * Post-process the given JAX-RPC port stub. Called by {@link #prepare}. + *

The default implementation is empty. + *

Just applied when actually creating a JAX-RPC port stub, in case of a + * compliant port interface. Else, JAX-RPC dynamic calls will be used. + * @param stub the current JAX-RPC port stub + * (can be cast to an implementation-specific class if necessary) + * @see #setPortInterface + * @see #postProcessJaxRpcCall + */ + protected void postProcessPortStub(Stub stub) { + } + + /** + * Return the underlying JAX-RPC port stub that this interceptor delegates to + * for each method invocation on the proxy. + */ + protected Remote getPortStub() { + return this.portStub; + } + + + /** + * Translates the method invocation into a JAX-RPC service invocation. + *

Prepares the service on the fly, if necessary, in case of lazy + * lookup or a connect failure having happened. + * @see #prepare() + * @see #doInvoke + */ + public Object invoke(MethodInvocation invocation) throws Throwable { + if (AopUtils.isToStringMethod(invocation.getMethod())) { + return "JAX-RPC proxy for port [" + getPortName() + "] of service [" + getServiceName() + "]"; + } + // Lazily prepare service and stub if necessary. + synchronized (this.preparationMonitor) { + if (!isPrepared()) { + prepare(); + } + } + return doInvoke(invocation); + } + + /** + * Perform a JAX-RPC service invocation based on the given method invocation. + *

Uses traditional RMI stub invocation if a JAX-RPC port stub is available; + * falls back to JAX-RPC dynamic calls else. + * @param invocation the AOP method invocation + * @return the invocation result, if any + * @throws Throwable in case of invocation failure + * @see #getPortStub() + * @see #doInvoke(org.aopalliance.intercept.MethodInvocation, java.rmi.Remote) + * @see #performJaxRpcCall(org.aopalliance.intercept.MethodInvocation, javax.xml.rpc.Service) + */ + protected Object doInvoke(MethodInvocation invocation) throws Throwable { + Remote stub = getPortStub(); + try { + if (stub != null) { + // JAX-RPC port stub available -> traditional RMI stub invocation. + if (logger.isTraceEnabled()) { + logger.trace("Invoking operation '" + invocation.getMethod().getName() + "' on JAX-RPC port stub"); + } + return doInvoke(invocation, stub); + } + else { + // No JAX-RPC stub -> using JAX-RPC dynamic calls. + if (logger.isTraceEnabled()) { + logger.trace("Invoking operation '" + invocation.getMethod().getName() + "' as JAX-RPC dynamic call"); + } + return performJaxRpcCall(invocation, this.serviceToUse); + } + } + catch (RemoteException ex) { + throw handleRemoteException(invocation.getMethod(), ex); + } + catch (SOAPFaultException ex) { + throw new JaxRpcSoapFaultException(ex); + } + catch (JAXRPCException ex) { + throw new RemoteProxyFailureException("Invalid JAX-RPC call configuration", ex); + } + } + + /** + * Perform a JAX-RPC service invocation on the given port stub. + * @param invocation the AOP method invocation + * @param portStub the RMI port stub to invoke + * @return the invocation result, if any + * @throws Throwable in case of invocation failure + * @see #getPortStub() + * @see #doInvoke(org.aopalliance.intercept.MethodInvocation, java.rmi.Remote) + * @see #performJaxRpcCall + */ + protected Object doInvoke(MethodInvocation invocation, Remote portStub) throws Throwable { + try { + return RmiClientInterceptorUtils.invokeRemoteMethod(invocation, portStub); + } + catch (InvocationTargetException ex) { + throw ex.getTargetException(); + } + } + + /** + * Perform a JAX-RPC dynamic call for the given AOP method invocation. + * Delegates to {@link #prepareJaxRpcCall} and + * {@link #postProcessJaxRpcCall} for setting up the call object. + *

The default implementation uses method name as JAX-RPC operation name + * and method arguments as arguments for the JAX-RPC call. Can be + * overridden in subclasses for custom operation names and/or arguments. + * @param invocation the current AOP MethodInvocation that should + * be converted to a JAX-RPC call + * @param service the JAX-RPC Service to use for the call + * @return the return value of the invocation, if any + * @throws Throwable the exception thrown by the invocation, if any + * @see #prepareJaxRpcCall + * @see #postProcessJaxRpcCall + */ + protected Object performJaxRpcCall(MethodInvocation invocation, Service service) throws Throwable { + Method method = invocation.getMethod(); + QName portQName = this.portQName; + + // Create JAX-RPC call object, using the method name as operation name. + // Synchronized because of non-thread-safe Axis implementation! + Call call = null; + synchronized (service) { + call = service.createCall(portQName, method.getName()); + } + + // Apply properties to JAX-RPC stub. + prepareJaxRpcCall(call); + + // Allow for custom post-processing in subclasses. + postProcessJaxRpcCall(call, invocation); + + // Perform actual invocation. + return call.invoke(invocation.getArguments()); + } + + /** + * Prepare the given JAX-RPC call, applying properties to it. Called by {@link #invoke}. + *

Just applied when actually using JAX-RPC dynamic calls, i.e. if no compliant + * port interface was specified. Else, a JAX-RPC port stub will be used. + * @param call the current JAX-RPC call object + * @see #setUsername + * @see #setPassword + * @see #setEndpointAddress + * @see #setMaintainSession + * @see #setCustomProperties + * @see #setPortInterface + * @see #preparePortStub + */ + protected void prepareJaxRpcCall(Call call) { + String username = getUsername(); + if (username != null) { + call.setProperty(Call.USERNAME_PROPERTY, username); + } + String password = getPassword(); + if (password != null) { + call.setProperty(Call.PASSWORD_PROPERTY, password); + } + String endpointAddress = getEndpointAddress(); + if (endpointAddress != null) { + call.setTargetEndpointAddress(endpointAddress); + } + if (isMaintainSession()) { + call.setProperty(Call.SESSION_MAINTAIN_PROPERTY, Boolean.TRUE); + } + if (this.customPropertyMap != null) { + for (Iterator it = this.customPropertyMap.keySet().iterator(); it.hasNext();) { + String key = (String) it.next(); + call.setProperty(key, this.customPropertyMap.get(key)); + } + } + } + + /** + * Post-process the given JAX-RPC call. Called by {@link #invoke}. + *

The default implementation is empty. + *

Just applied when actually using JAX-RPC dynamic calls, i.e. if no compliant + * port interface was specified. Else, a JAX-RPC port stub will be used. + * @param call the current JAX-RPC call object + * (can be cast to an implementation-specific class if necessary) + * @param invocation the current AOP MethodInvocation that the call was + * created for (can be used to check method name, method parameters + * and/or passed-in arguments) + * @see #setPortInterface + * @see #postProcessPortStub + */ + protected void postProcessJaxRpcCall(Call call, MethodInvocation invocation) { + } + + /** + * Handle the given RemoteException that was thrown from a JAX-RPC port stub + * or JAX-RPC call invocation. + * @param method the service interface method that we invoked + * @param ex the original RemoteException + * @return the exception to rethrow (may be the original RemoteException + * or an extracted/wrapped exception, but never null) + */ + protected Throwable handleRemoteException(Method method, RemoteException ex) { + boolean isConnectFailure = isConnectFailure(ex); + if (isConnectFailure && this.refreshServiceAfterConnectFailure) { + reset(); + } + Throwable cause = ex.getCause(); + if (cause != null && ReflectionUtils.declaresException(method, cause.getClass())) { + if (logger.isDebugEnabled()) { + logger.debug("Rethrowing wrapped exception of type [" + cause.getClass().getName() + "] as-is"); + } + // Declared on the service interface: probably a wrapped business exception. + return ex.getCause(); + } + else { + // Throw either a RemoteAccessException or the original RemoteException, + // depending on what the service interface declares. + return RmiClientInterceptorUtils.convertRmiAccessException( + method, ex, isConnectFailure, this.portQName.toString()); + } + } + + /** + * Determine whether the given RMI exception indicates a connect failure. + *

The default implementation returns true unless the + * exception class name (or exception superclass name) contains the term + * "Fault" (e.g. "AxisFault"), assuming that the JAX-RPC provider only + * throws RemoteException in case of WSDL faults and connect failures. + * @param ex the RMI exception to check + * @return whether the exception should be treated as connect failure + * @see org.springframework.remoting.rmi.RmiClientInterceptorUtils#isConnectFailure + */ + protected boolean isConnectFailure(RemoteException ex) { + return (ex.getClass().getName().indexOf("Fault") == -1 && + ex.getClass().getSuperclass().getName().indexOf("Fault") == -1); + } + +} Index: 3rdParty_sources/spring/org/springframework/remoting/jaxrpc/JaxRpcPortProxyFactoryBean.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/remoting/jaxrpc/JaxRpcPortProxyFactoryBean.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/remoting/jaxrpc/JaxRpcPortProxyFactoryBean.java 17 Aug 2012 15:16:06 -0000 1.1 @@ -0,0 +1,87 @@ +/* + * 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.remoting.jaxrpc; + +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} for a specific port of a + * JAX-RPC service. Exposes a proxy for the port, to be used for bean references. + * Inherits configuration properties from {@link JaxRpcPortClientInterceptor}. + * + *

This factory is typically used with an RMI service interface. Alternatively, + * this factory can also proxy a JAX-RPC service with a matching non-RMI business + * interface, i.e. an interface that mirrors the RMI service methods but does not + * declare RemoteExceptions. In the latter case, RemoteExceptions thrown by the + * JAX-RPC stub will automatically get converted to Spring's unchecked + * RemoteAccessException. + * + *

If exposing the JAX-RPC port interface (i.e. an RMI interface) directly, + * setting "serviceInterface" is sufficient. If exposing a non-RMI business + * interface, the business interface needs to be set as "serviceInterface", + * and the JAX-RPC port interface as "portInterface". + * + * @author Juergen Hoeller + * @since 15.12.2003 + * @see #setServiceInterface + * @see #setPortInterface + * @see LocalJaxRpcServiceFactoryBean + */ +public class JaxRpcPortProxyFactoryBean extends JaxRpcPortClientInterceptor + implements FactoryBean, BeanClassLoaderAware { + + private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader(); + + private Object serviceProxy; + + + public void setBeanClassLoader(ClassLoader classLoader) { + this.beanClassLoader = classLoader; + } + + public void afterPropertiesSet() { + if (getServiceInterface() == null) { + // Use JAX-RPC port interface (a traditional RMI interface) + // as service interface if none explicitly specified. + if (getPortInterface() != null) { + setServiceInterface(getPortInterface()); + } + else { + throw new IllegalArgumentException("Property 'serviceInterface' is required"); + } + } + super.afterPropertiesSet(); + this.serviceProxy = new ProxyFactory(getServiceInterface(), this).getProxy(this.beanClassLoader); + } + + + public Object getObject() { + return this.serviceProxy; + } + + public Class getObjectType() { + return getServiceInterface(); + } + + public boolean isSingleton() { + return true; + } + +} Index: 3rdParty_sources/spring/org/springframework/remoting/jaxrpc/JaxRpcServicePostProcessor.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/remoting/jaxrpc/JaxRpcServicePostProcessor.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/remoting/jaxrpc/JaxRpcServicePostProcessor.java 17 Aug 2012 15:16:06 -0000 1.1 @@ -0,0 +1,51 @@ +/* + * 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.remoting.jaxrpc; + +import javax.xml.rpc.Service; + +/** + * Callback interface for post-processing a JAX-RPC Service. + * + *

Implementations can be registered with {@link LocalJaxRpcServiceFactory} + * or one of its subclasses: {@link LocalJaxRpcServiceFactoryBean}, + * {@link JaxRpcPortClientInterceptor}, or {@link JaxRpcPortProxyFactoryBean}. + * + *

Useful, for example, to register custom type mappings. See the + * {@link org.springframework.remoting.jaxrpc.support.AxisBeanMappingServicePostProcessor} + * class that registers Axis-specific bean mappings for specified bean classes. + * This is defined for the domain objects in the JPetStore same application, + * for example. + * + * @author Juergen Hoeller + * @since 1.1.4 + * @see LocalJaxRpcServiceFactory#setServicePostProcessors + * @see LocalJaxRpcServiceFactoryBean#setServicePostProcessors + * @see JaxRpcPortClientInterceptor#setServicePostProcessors + * @see JaxRpcPortProxyFactoryBean#setServicePostProcessors + * @see javax.xml.rpc.Service#getTypeMappingRegistry + */ +public interface JaxRpcServicePostProcessor { + + /** + * Post-process the given JAX-RPC {@link Service}. + * @param service the current JAX-RPC Service + * (can be cast to an implementation-specific class if necessary) + */ + void postProcessJaxRpcService(Service service); + +} Index: 3rdParty_sources/spring/org/springframework/remoting/jaxrpc/JaxRpcSoapFaultException.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/remoting/jaxrpc/JaxRpcSoapFaultException.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/remoting/jaxrpc/JaxRpcSoapFaultException.java 17 Aug 2012 15:16:06 -0000 1.1 @@ -0,0 +1,65 @@ +/* + * 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.remoting.jaxrpc; + +import javax.xml.namespace.QName; +import javax.xml.rpc.soap.SOAPFaultException; + +import org.springframework.remoting.soap.SoapFaultException; + +/** + * Spring SoapFaultException adapter for the JAX-RPC + * {@link javax.xml.rpc.soap.SOAPFaultException} class. + * + * @author Juergen Hoeller + * @since 2.5 + */ +public class JaxRpcSoapFaultException extends SoapFaultException { + + /** + * Constructor for JaxRpcSoapFaultException. + * @param original the original JAX-RPC SOAPFaultException to wrap + */ + public JaxRpcSoapFaultException(SOAPFaultException original) { + super(original.getMessage(), original); + } + + /** + * Return the wrapped JAX-RPC SOAPFaultException. + */ + public final SOAPFaultException getOriginalException() { + return (SOAPFaultException) getCause(); + } + + + public String getFaultCode() { + return getOriginalException().getFaultCode().toString(); + } + + public QName getFaultCodeAsQName() { + return getOriginalException().getFaultCode(); + } + + public String getFaultString() { + return getOriginalException().getFaultString(); + } + + public String getFaultActor() { + return getOriginalException().getFaultActor(); + } + +} Index: 3rdParty_sources/spring/org/springframework/remoting/jaxrpc/LocalJaxRpcServiceFactory.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/remoting/jaxrpc/LocalJaxRpcServiceFactory.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/remoting/jaxrpc/LocalJaxRpcServiceFactory.java 17 Aug 2012 15:16:06 -0000 1.1 @@ -0,0 +1,321 @@ +/* + * 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.remoting.jaxrpc; + +import java.net.URL; +import java.util.Properties; + +import javax.xml.namespace.QName; +import javax.xml.rpc.Service; +import javax.xml.rpc.ServiceException; +import javax.xml.rpc.ServiceFactory; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import org.springframework.beans.BeanUtils; + +/** + * Factory for locally defined JAX-RPC {@link javax.xml.rpc.Service} references. + * Uses a JAX-RPC {@link javax.xml.rpc.ServiceFactory} underneath. + * + *

Serves as base class for {@link LocalJaxRpcServiceFactoryBean} as well as + * {@link JaxRpcPortClientInterceptor} and {@link JaxRpcPortProxyFactoryBean}. + * + * @author Juergen Hoeller + * @since 15.12.2003 + * @see javax.xml.rpc.ServiceFactory + * @see javax.xml.rpc.Service + * @see LocalJaxRpcServiceFactoryBean + * @see JaxRpcPortClientInterceptor + * @see JaxRpcPortProxyFactoryBean + */ +public class LocalJaxRpcServiceFactory { + + /** Logger available to subclasses */ + protected final Log logger = LogFactory.getLog(getClass()); + + private ServiceFactory serviceFactory; + + private Class serviceFactoryClass; + + private URL wsdlDocumentUrl; + + private String namespaceUri; + + private String serviceName; + + private Class jaxRpcServiceInterface; + + private Properties jaxRpcServiceProperties; + + private JaxRpcServicePostProcessor[] servicePostProcessors; + + + /** + * Set the ServiceFactory instance to use. + *

This is an alternative to the common "serviceFactoryClass" property, + * allowing for a pre-initialized ServiceFactory instance to be specified. + * @see #setServiceFactoryClass + */ + public void setServiceFactory(ServiceFactory serviceFactory) { + this.serviceFactory = serviceFactory; + } + + /** + * Return the specified ServiceFactory instance, if any. + */ + public ServiceFactory getServiceFactory() { + return this.serviceFactory; + } + + /** + * Set the ServiceFactory class to use, for example + * "org.apache.axis.client.ServiceFactory". + *

Does not need to be set if the JAX-RPC implementation has registered + * itself with the JAX-RPC system property "SERVICEFACTORY_PROPERTY". + * @see javax.xml.rpc.ServiceFactory + */ + public void setServiceFactoryClass(Class serviceFactoryClass) { + if (serviceFactoryClass != null && !ServiceFactory.class.isAssignableFrom(serviceFactoryClass)) { + throw new IllegalArgumentException("'serviceFactoryClass' must implement [javax.xml.rpc.ServiceFactory]"); + } + this.serviceFactoryClass = serviceFactoryClass; + } + + /** + * Return the ServiceFactory class to use, or null if default. + */ + public Class getServiceFactoryClass() { + return this.serviceFactoryClass; + } + + /** + * Set the URL of the WSDL document that describes the service. + */ + public void setWsdlDocumentUrl(URL wsdlDocumentUrl) { + this.wsdlDocumentUrl = wsdlDocumentUrl; + } + + /** + * Return the URL of the WSDL document that describes the service. + */ + public URL getWsdlDocumentUrl() { + return this.wsdlDocumentUrl; + } + + /** + * Set the namespace URI of the service. + * Corresponds to the WSDL "targetNamespace". + */ + public void setNamespaceUri(String namespaceUri) { + this.namespaceUri = (namespaceUri != null ? namespaceUri.trim() : null); + } + + /** + * Return the namespace URI of the service. + */ + public String getNamespaceUri() { + return this.namespaceUri; + } + + /** + * Set the name of the service to look up. + * Corresponds to the "wsdl:service" name. + * @see javax.xml.rpc.ServiceFactory#createService(javax.xml.namespace.QName) + * @see javax.xml.rpc.ServiceFactory#createService(java.net.URL, javax.xml.namespace.QName) + * @see javax.xml.rpc.ServiceFactory#loadService(java.net.URL, javax.xml.namespace.QName, java.util.Properties) + */ + public void setServiceName(String serviceName) { + this.serviceName = serviceName; + } + + /** + * Return the name of the service. + */ + public String getServiceName() { + return this.serviceName; + } + + /** + * Set the JAX-RPC service interface to use for looking up the service. + * If specified, this will override a "serviceName" setting. + *

The specified interface will usually be a generated JAX-RPC service + * interface that directly corresponds to the WSDL service declaration. + * Note that this is not a port interface or the application-level service + * interface to be exposed by a port proxy! + *

Only supported by JAX-RPC 1.1 providers. + * @see #setServiceName + * @see javax.xml.rpc.ServiceFactory#loadService(Class) + * @see javax.xml.rpc.ServiceFactory#loadService(java.net.URL, Class, java.util.Properties) + */ + public void setJaxRpcServiceInterface(Class jaxRpcServiceInterface) { + this.jaxRpcServiceInterface = jaxRpcServiceInterface; + } + + /** + * Return the JAX-RPC service interface to use for looking up the service. + */ + public Class getJaxRpcServiceInterface() { + return this.jaxRpcServiceInterface; + } + + /** + * Set JAX-RPC service properties to be passed to the ServiceFactory, if any. + *

Only supported by JAX-RPC 1.1 providers. + * @see javax.xml.rpc.ServiceFactory#loadService(java.net.URL, javax.xml.namespace.QName, java.util.Properties) + * @see javax.xml.rpc.ServiceFactory#loadService(java.net.URL, Class, java.util.Properties) + */ + public void setJaxRpcServiceProperties(Properties jaxRpcServiceProperties) { + this.jaxRpcServiceProperties = jaxRpcServiceProperties; + } + + /** + * Return JAX-RPC service properties to be passed to the ServiceFactory, if any. + */ + public Properties getJaxRpcServiceProperties() { + return this.jaxRpcServiceProperties; + } + + /** + * Set the JaxRpcServicePostProcessors to be applied to JAX-RPC Service + * instances created by this factory. + *

Such post-processors can, for example, register custom type mappings. + * They are reusable across all pre-built subclasses of this factory: + * LocalJaxRpcServiceFactoryBean, JaxRpcPortClientInterceptor, + * JaxRpcPortProxyFactoryBean. + * @see LocalJaxRpcServiceFactoryBean + * @see JaxRpcPortClientInterceptor + * @see JaxRpcPortProxyFactoryBean + */ + public void setServicePostProcessors(JaxRpcServicePostProcessor[] servicePostProcessors) { + this.servicePostProcessors = servicePostProcessors; + } + + /** + * Return the JaxRpcServicePostProcessors to be applied to JAX-RPC Service + * instances created by this factory. + */ + public JaxRpcServicePostProcessor[] getServicePostProcessors() { + return this.servicePostProcessors; + } + + + /** + * Create a JAX-RPC Service according to the parameters of this factory. + * @see #setServiceName + * @see #setWsdlDocumentUrl + * @see #postProcessJaxRpcService + */ + public Service createJaxRpcService() throws ServiceException { + ServiceFactory serviceFactory = getServiceFactory(); + if (serviceFactory == null) { + serviceFactory = createServiceFactory(); + } + + // Create service based on this factory's settings. + Service service = createService(serviceFactory); + + // Allow for custom post-processing in subclasses. + postProcessJaxRpcService(service); + + return service; + } + + /** + * Return a QName for the given name, relative to the namespace URI + * of this factory, if given. + * @see #setNamespaceUri + */ + protected QName getQName(String name) { + return (getNamespaceUri() != null ? new QName(getNamespaceUri(), name) : new QName(name)); + } + + /** + * Create a JAX-RPC ServiceFactory, either of the specified class + * or the default. + * @throws ServiceException if thrown by JAX-RPC methods + * @see #setServiceFactoryClass + * @see javax.xml.rpc.ServiceFactory#newInstance() + */ + protected ServiceFactory createServiceFactory() throws ServiceException { + if (getServiceFactoryClass() != null) { + return (ServiceFactory) BeanUtils.instantiateClass(getServiceFactoryClass()); + } + else { + return ServiceFactory.newInstance(); + } + } + + /** + * Actually create the JAX-RPC Service instance, + * based on this factory's settings. + * @param serviceFactory the JAX-RPC ServiceFactory to use + * @return the newly created JAX-RPC Service + * @throws ServiceException if thrown by JAX-RPC methods + * @see javax.xml.rpc.ServiceFactory#createService + * @see javax.xml.rpc.ServiceFactory#loadService + */ + protected Service createService(ServiceFactory serviceFactory) throws ServiceException { + if (getServiceName() == null && getJaxRpcServiceInterface() == null) { + throw new IllegalArgumentException("Either 'serviceName' or 'jaxRpcServiceInterface' is required"); + } + + if (getJaxRpcServiceInterface() != null) { + // Create service via generated JAX-RPC service interface. + // Only supported on JAX-RPC 1.1 + if (getWsdlDocumentUrl() != null || getJaxRpcServiceProperties() != null) { + return serviceFactory.loadService( + getWsdlDocumentUrl(), getJaxRpcServiceInterface(), getJaxRpcServiceProperties()); + } + return serviceFactory.loadService(getJaxRpcServiceInterface()); + } + + // Create service via specified JAX-RPC service name. + QName serviceQName = getQName(getServiceName()); + if (getJaxRpcServiceProperties() != null) { + // Only supported on JAX-RPC 1.1 + return serviceFactory.loadService(getWsdlDocumentUrl(), serviceQName, getJaxRpcServiceProperties()); + } + if (getWsdlDocumentUrl() != null) { + return serviceFactory.createService(getWsdlDocumentUrl(), serviceQName); + } + return serviceFactory.createService(serviceQName); + } + + /** + * Post-process the given JAX-RPC Service. Called by {@link #createJaxRpcService}. + * Useful, for example, to register custom type mappings. + *

The default implementation delegates to all registered + * {@link JaxRpcServicePostProcessor JaxRpcServicePostProcessors}. + * It is usually preferable to implement custom type mappings etc there rather + * than in a subclass of this factory, to allow for reuse of the post-processors. + * @param service the current JAX-RPC Service + * (can be cast to an implementation-specific class if necessary) + * @see #setServicePostProcessors + * @see javax.xml.rpc.Service#getTypeMappingRegistry() + */ + protected void postProcessJaxRpcService(Service service) { + JaxRpcServicePostProcessor[] postProcessors = getServicePostProcessors(); + if (postProcessors != null) { + for (int i = 0; i < postProcessors.length; i++) { + postProcessors[i].postProcessJaxRpcService(service); + } + } + } + +} Index: 3rdParty_sources/spring/org/springframework/remoting/jaxrpc/LocalJaxRpcServiceFactoryBean.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/remoting/jaxrpc/LocalJaxRpcServiceFactoryBean.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/remoting/jaxrpc/LocalJaxRpcServiceFactoryBean.java 17 Aug 2012 15:16:06 -0000 1.1 @@ -0,0 +1,62 @@ +/* + * 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.remoting.jaxrpc; + +import javax.xml.rpc.Service; +import javax.xml.rpc.ServiceException; + +import org.springframework.beans.factory.FactoryBean; +import org.springframework.beans.factory.InitializingBean; + +/** + * {@link org.springframework.beans.factory.FactoryBean} for locally + * defined JAX-RPC Service references. + * Uses {@link LocalJaxRpcServiceFactory}'s facilities underneath. + * + *

Alternatively, JAX-RPC Service references can be looked up + * in the JNDI environment of the J2EE container. + * + * @author Juergen Hoeller + * @since 15.12.2003 + * @see javax.xml.rpc.Service + * @see org.springframework.jndi.JndiObjectFactoryBean + * @see JaxRpcPortProxyFactoryBean + */ +public class LocalJaxRpcServiceFactoryBean extends LocalJaxRpcServiceFactory + implements FactoryBean, InitializingBean { + + private Service service; + + + public void afterPropertiesSet() throws ServiceException { + this.service = createJaxRpcService(); + } + + + public Object getObject() throws Exception { + return this.service; + } + + public Class getObjectType() { + return (this.service != null ? this.service.getClass() : Service.class); + } + + public boolean isSingleton() { + return true; + } + +} Index: 3rdParty_sources/spring/org/springframework/remoting/jaxrpc/ServletEndpointSupport.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/remoting/jaxrpc/ServletEndpointSupport.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/remoting/jaxrpc/ServletEndpointSupport.java 17 Aug 2012 15:16:06 -0000 1.1 @@ -0,0 +1,150 @@ +/* + * 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.remoting.jaxrpc; + +import java.io.File; + +import javax.servlet.ServletContext; +import javax.xml.rpc.ServiceException; +import javax.xml.rpc.server.ServiceLifecycle; +import javax.xml.rpc.server.ServletEndpointContext; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import org.springframework.context.ApplicationContext; +import org.springframework.context.support.MessageSourceAccessor; +import org.springframework.web.context.WebApplicationContext; +import org.springframework.web.context.support.WebApplicationContextUtils; +import org.springframework.web.util.WebUtils; + +/** + * Convenience base class for JAX-RPC servlet endpoint implementations. + * Provides a reference to the current Spring application context, + * e.g. for bean lookup or resource loading. + * + *

The Web Service servlet needs to run in the same web application + * as the Spring context to allow for access to Spring's facilities. + * In case of Axis, copy the AxisServlet definition into your web.xml, + * and set up the endpoint in "server-config.wsdd" (or use the deploy tool). + * + *

This class does not extend + * {@link org.springframework.web.context.support.WebApplicationObjectSupport} + * to not expose any public setters. For some reason, Axis tries to + * resolve public setters in a special way... + * + *

JAX-RPC service endpoints are usually required to implement an + * RMI port interface. However, many JAX-RPC implementations accept plain + * service endpoint classes too, avoiding the need to maintain an RMI port + * interface in addition to an existing non-RMI business interface. + * Therefore, implementing the business interface will usually be sufficient. + * + * @author Juergen Hoeller + * @since 16.12.2003 + * @see #init + * @see #getWebApplicationContext + */ +public abstract class ServletEndpointSupport implements ServiceLifecycle { + + protected final Log logger = LogFactory.getLog(getClass()); + + private ServletEndpointContext servletEndpointContext; + + private WebApplicationContext webApplicationContext; + + private MessageSourceAccessor messageSourceAccessor; + + + /** + * Initialize this JAX-RPC servlet endpoint. + * Calls onInit after successful context initialization. + * @param context ServletEndpointContext + * @throws ServiceException if the context is not a ServletEndpointContext + * @see #onInit + */ + public final void init(Object context) throws ServiceException { + if (!(context instanceof ServletEndpointContext)) { + throw new ServiceException("ServletEndpointSupport needs ServletEndpointContext, not [" + context + "]"); + } + this.servletEndpointContext = (ServletEndpointContext) context; + ServletContext servletContext = this.servletEndpointContext.getServletContext(); + this.webApplicationContext = WebApplicationContextUtils.getRequiredWebApplicationContext(servletContext); + this.messageSourceAccessor = new MessageSourceAccessor(this.webApplicationContext); + onInit(); + } + + /** + * Return the current JAX-RPC ServletEndpointContext. + */ + protected final ServletEndpointContext getServletEndpointContext() { + return this.servletEndpointContext; + } + + /** + * Return the current Spring ApplicationContext. + */ + protected final ApplicationContext getApplicationContext() { + return this.webApplicationContext; + } + + /** + * Return the current Spring WebApplicationContext. + */ + protected final WebApplicationContext getWebApplicationContext() { + return this.webApplicationContext; + } + + /** + * Return a MessageSourceAccessor for the application context + * used by this object, for easy message access. + */ + protected final MessageSourceAccessor getMessageSourceAccessor() { + return this.messageSourceAccessor; + } + + /** + * Return the current ServletContext. + */ + protected final ServletContext getServletContext() { + return this.webApplicationContext.getServletContext(); + } + + /** + * Return the temporary directory for the current web application, + * as provided by the servlet container. + * @return the File representing the temporary directory + */ + protected final File getTempDir() { + return WebUtils.getTempDir(getServletContext()); + } + + /** + * Callback for custom initialization after the context has been set up. + * @throws ServiceException if initialization failed + */ + protected void onInit() throws ServiceException { + } + + + /** + * This implementation of destroy is empty. + * Can be overridden in subclasses. + */ + public void destroy() { + } + +} Index: 3rdParty_sources/spring/org/springframework/remoting/jaxrpc/package.html =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/remoting/jaxrpc/package.html,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/remoting/jaxrpc/package.html 17 Aug 2012 15:16:06 -0000 1.1 @@ -0,0 +1,10 @@ + + + +Remoting classes for Web Services via JAX-RPC. +This package provides proxy factories for accessing JAX-RPC +services and ports, and a support class for implementing +JAX-RPC Servlet endpoints. + + + Index: 3rdParty_sources/spring/org/springframework/remoting/jaxrpc/support/AxisBeanMappingServicePostProcessor.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/remoting/jaxrpc/support/AxisBeanMappingServicePostProcessor.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/remoting/jaxrpc/support/AxisBeanMappingServicePostProcessor.java 17 Aug 2012 15:16:17 -0000 1.1 @@ -0,0 +1,210 @@ +/* + * 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.remoting.jaxrpc.support; + +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.Properties; + +import javax.xml.namespace.QName; +import javax.xml.rpc.Service; +import javax.xml.rpc.encoding.TypeMapping; +import javax.xml.rpc.encoding.TypeMappingRegistry; + +import org.apache.axis.encoding.ser.BeanDeserializerFactory; +import org.apache.axis.encoding.ser.BeanSerializerFactory; + +import org.springframework.beans.factory.BeanClassLoaderAware; +import org.springframework.remoting.jaxrpc.JaxRpcServicePostProcessor; +import org.springframework.util.ClassUtils; + +/** + * Axis-specific {@link JaxRpcServicePostProcessor} that registers bean + * mappings for domain objects that follow the JavaBean pattern. + * + *

The same mappings are usually also registered at the server in + * Axis' "server-config.wsdd" file. + * + *

To be registered as a service post-processor on a + * {@link org.springframework.remoting.jaxrpc.LocalJaxRpcServiceFactoryBean} or + * {@link org.springframework.remoting.jaxrpc.JaxRpcPortProxyFactoryBean}, + * carrying appropriate configuration. + * + *

Note: Without such explicit bean mappings, a complex type like a + * domain object cannot be transferred via SOAP. + * + * @author Juergen Hoeller + * @since 2.0 + * @see org.apache.axis.encoding.ser.BeanSerializerFactory + * @see org.apache.axis.encoding.ser.BeanDeserializerFactory + * @see org.springframework.remoting.jaxrpc.LocalJaxRpcServiceFactoryBean#setServicePostProcessors + * @see org.springframework.remoting.jaxrpc.JaxRpcPortProxyFactoryBean#setServicePostProcessors + */ +public class AxisBeanMappingServicePostProcessor implements JaxRpcServicePostProcessor, BeanClassLoaderAware { + + private String encodingStyleUri; + + private String typeNamespaceUri; + + private Map beanMappings; + + private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader(); + + + /** + * Set the encoding style URI to use for the type mapping. + *

A typical value is "http://schemas.xmlsoap.org/soap/encoding/", + * as suggested by the JAX-RPC javadoc. However, note that the default + * behavior of this post-processor is to register the type mapping + * as JAX-RPC default if no explicit encoding style URI is given. + * @see javax.xml.rpc.encoding.TypeMappingRegistry#register + * @see javax.xml.rpc.encoding.TypeMappingRegistry#registerDefault + */ + public void setEncodingStyleUri(String encodingStyleUri) { + this.encodingStyleUri = encodingStyleUri; + } + + /** + * Set the application-specific namespace to use for XML types, + * for example "urn:JPetStore". + * @see javax.xml.rpc.encoding.TypeMapping#register + */ + public void setTypeNamespaceUri(String typeNamespaceUri) { + this.typeNamespaceUri = typeNamespaceUri; + } + + /** + * Specify the bean mappings to register as String-String pairs, + * with the Java type name as key and the WSDL type name as value. + */ + public void setBeanMappings(Properties beanMappingProps) { + if (beanMappingProps != null) { + this.beanMappings = new HashMap(beanMappingProps.size()); + Enumeration propertyNames = beanMappingProps.propertyNames(); + while (propertyNames.hasMoreElements()) { + String javaTypeName = (String) propertyNames.nextElement(); + String wsdlTypeName = beanMappingProps.getProperty(javaTypeName); + this.beanMappings.put(javaTypeName, wsdlTypeName); + } + } + else { + this.beanMappings = null; + } + } + + /** + * Specify the bean mappings to register as Java types, + * with the WSDL type names inferred from the Java type names + * (using the short, that is, non-fully-qualified class name). + */ + public void setBeanClasses(Class[] beanClasses) { + if (beanClasses != null) { + this.beanMappings = new HashMap(beanClasses.length); + for (int i = 0; i < beanClasses.length; i++) { + Class beanClass = beanClasses[i]; + String wsdlTypeName = ClassUtils.getShortName(beanClass); + this.beanMappings.put(beanClass, wsdlTypeName); + } + } + else { + this.beanMappings = null; + } + } + + public void setBeanClassLoader(ClassLoader beanClassLoader) { + this.beanClassLoader = beanClassLoader; + } + + + /** + * Register the specified bean mappings on the given Service's + * {@link TypeMappingRegistry}. + * @see javax.xml.rpc.Service#getTypeMappingRegistry() + * @see #setBeanMappings + * @see #registerBeanMappings(javax.xml.rpc.encoding.TypeMapping) + */ + public void postProcessJaxRpcService(Service service) { + TypeMappingRegistry registry = service.getTypeMappingRegistry(); + TypeMapping mapping = registry.createTypeMapping(); + + registerBeanMappings(mapping); + + if (this.encodingStyleUri != null) { + registry.register(this.encodingStyleUri, mapping); + } + else { + registry.registerDefault(mapping); + } + } + + /** + * Perform the actual bean mapping registration. + * @param mapping the JAX-RPC {@link TypeMapping} to operate on + * @see #setBeanMappings + * @see #registerBeanMapping(javax.xml.rpc.encoding.TypeMapping, Class, String) + */ + protected void registerBeanMappings(TypeMapping mapping) { + if (this.beanMappings != null) { + for (Iterator it = this.beanMappings.entrySet().iterator(); it.hasNext();) { + Map.Entry entry = (Map.Entry) it.next(); + Object key = entry.getKey(); + Class javaType = null; + if (key instanceof Class) { + javaType = (Class) key; + } + else { + javaType = ClassUtils.resolveClassName((String) key, this.beanClassLoader); + } + String wsdlTypeName = (String) entry.getValue(); + registerBeanMapping(mapping, javaType, wsdlTypeName); + } + } + } + + /** + * Register a bean mapping for the given Java type and WSDL type name. + * @param mapping the JAX-RPC {@link TypeMapping} to operate on + * @param javaType the Java type + * @param wsdlTypeName the WSDL type name (as a {@link String}) + */ + protected void registerBeanMapping(TypeMapping mapping, Class javaType, String wsdlTypeName) { + registerBeanMapping(mapping, javaType, getTypeQName(wsdlTypeName)); + } + + /** + * Register a bean mapping for the given Java type and WSDL type. + * @param mapping the JAX-RPC {@link TypeMapping} to operate on + * @param javaType the Java type + * @param wsdlType the WSDL type (as XML {@link QName}) + */ + protected void registerBeanMapping(TypeMapping mapping, Class javaType, QName wsdlType) { + mapping.register(javaType, wsdlType, + new BeanSerializerFactory(javaType, wsdlType), + new BeanDeserializerFactory(javaType, wsdlType)); + } + + /** + * Return a {@link QName} for the given name, relative to the + * {@link #setTypeNamespaceUri namespace URI} of this post-processor, if given. + */ + protected final QName getTypeQName(String name) { + return (this.typeNamespaceUri != null ? new QName(this.typeNamespaceUri, name) : new QName(name)); + } + +} Index: 3rdParty_sources/spring/org/springframework/remoting/jaxrpc/support/package.html =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/remoting/jaxrpc/support/package.html,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/remoting/jaxrpc/support/package.html 17 Aug 2012 15:16:17 -0000 1.1 @@ -0,0 +1,8 @@ + + + +Support for specific JAX-RPC providers. Contains an Axis-specific +JaxRpcServicePostProcessor for declaratively registering bean mappings. + + + Index: 3rdParty_sources/spring/org/springframework/remoting/jaxws/AbstractJaxWsServiceExporter.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/remoting/jaxws/AbstractJaxWsServiceExporter.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/remoting/jaxws/AbstractJaxWsServiceExporter.java 17 Aug 2012 15:16:06 -0000 1.1 @@ -0,0 +1,148 @@ +/* + * 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.remoting.jaxws; + +import java.util.LinkedHashSet; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.Executor; + +import javax.jws.WebService; +import javax.xml.ws.Endpoint; + +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.core.task.TaskExecutor; +import org.springframework.core.task.support.ConcurrentExecutorAdapter; + +/** + * Abstract exporter for JAX-WS services, autodetecting annotated service beans + * (through the JAX-WS {@link javax.jws.WebService} annotation). Subclasses + * need to implement the {@link #publishEndpoint} template method for actual + * endpoint exposure. + * + * @author Juergen Hoeller + * @since 2.5.5 + * @see javax.jws.WebService + * @see javax.xml.ws.Endpoint + * @see SimpleJaxWsServiceExporter + * @see SimpleHttpServerJaxWsServiceExporter + */ +public abstract class AbstractJaxWsServiceExporter implements BeanFactoryAware, InitializingBean, DisposableBean { + + private Map endpointProperties; + + private Executor executor; + + private ListableBeanFactory beanFactory; + + private final Set publishedEndpoints = new LinkedHashSet(); + + + /** + * Set the property bag for the endpoint, including properties such as + * "javax.xml.ws.wsdl.service" or "javax.xml.ws.wsdl.port". + * @see javax.xml.ws.Endpoint#setProperties + * @see javax.xml.ws.Endpoint#WSDL_SERVICE + * @see javax.xml.ws.Endpoint#WSDL_PORT + */ + public void setEndpointProperties(Map endpointProperties) { + this.endpointProperties = endpointProperties; + } + + /** + * Set the JDK concurrent executor to use for dispatching incoming requests + * to exported service instances. + * @see javax.xml.ws.Endpoint#setExecutor + */ + public void setExecutor(Executor executor) { + this.executor = executor; + } + + /** + * Set the Spring TaskExecutor to use for dispatching incoming requests + * to exported service instances. + * @see javax.xml.ws.Endpoint#setExecutor + */ + public void setTaskExecutor(TaskExecutor executor) { + this.executor = new ConcurrentExecutorAdapter(executor); + } + + /** + * Obtains all web service beans and publishes them as JAX-WS endpoints. + */ + public void setBeanFactory(BeanFactory beanFactory) { + if (!(beanFactory instanceof ListableBeanFactory)) { + throw new IllegalStateException(getClass().getSimpleName() + " requires a ListableBeanFactory"); + } + this.beanFactory = (ListableBeanFactory) beanFactory; + } + + + /** + * Immediately publish all endpoints when fully configured. + * @see #publishEndpoints() + */ + public void afterPropertiesSet() throws Exception { + publishEndpoints(); + } + + /** + * Publish all {@link javax.jws.WebService} annotated beans in the + * containing BeanFactory. + * @see #publishEndpoint + */ + public void publishEndpoints() { + String[] beanNames = this.beanFactory.getBeanNamesForType(Object.class, false, false); + for (String beanName : beanNames) { + Class type = this.beanFactory.getType(beanName); + WebService annotation = type.getAnnotation(WebService.class); + if (annotation != null) { + Endpoint endpoint = Endpoint.create(this.beanFactory.getBean(beanName)); + if (this.endpointProperties != null) { + endpoint.setProperties(this.endpointProperties); + } + if (this.executor != null) { + endpoint.setExecutor(this.executor); + } + publishEndpoint(endpoint, annotation); + this.publishedEndpoints.add(endpoint); + } + } + } + + /** + * Actually publish the given endpoint. To be implemented by subclasses. + * @param endpoint the JAX-WS Endpoint object + * @param annotation the service bean's WebService annotation + */ + protected abstract void publishEndpoint(Endpoint endpoint, WebService annotation); + + + /** + * Stops all published endpoints, taking the web services offline. + */ + public void destroy() { + for (Endpoint endpoint : this.publishedEndpoints) { + endpoint.stop(); + } + } + +} Index: 3rdParty_sources/spring/org/springframework/remoting/jaxws/JaxWsPortClientInterceptor.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/remoting/jaxws/JaxWsPortClientInterceptor.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/remoting/jaxws/JaxWsPortClientInterceptor.java 17 Aug 2012 15:16:06 -0000 1.1 @@ -0,0 +1,426 @@ +/* + * 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.remoting.jaxws; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.Map; + +import javax.xml.namespace.QName; +import javax.xml.ws.BindingProvider; +import javax.xml.ws.ProtocolException; +import javax.xml.ws.Service; +import javax.xml.ws.WebServiceException; +import javax.xml.ws.soap.SOAPFaultException; + +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.remoting.RemoteAccessException; +import org.springframework.remoting.RemoteConnectFailureException; +import org.springframework.remoting.RemoteLookupFailureException; +import org.springframework.remoting.RemoteProxyFailureException; + +/** + * {@link org.aopalliance.intercept.MethodInterceptor} for accessing a + * specific port of a JAX-WS service. + * + *

Uses either {@link LocalJaxWsServiceFactory}'s facilities underneath, + * or takes an explicit reference to an existing JAX-WS Service instance + * (e.g. obtained via {@link org.springframework.jndi.JndiObjectFactoryBean}). + * + * @author Juergen Hoeller + * @since 2.5 + * @see #setPortName + * @see #setServiceInterface + * @see javax.xml.ws.Service#getPort + * @see org.springframework.remoting.RemoteAccessException + * @see org.springframework.jndi.JndiObjectFactoryBean + */ +public class JaxWsPortClientInterceptor extends LocalJaxWsServiceFactory + implements MethodInterceptor, InitializingBean { + + private Service jaxWsService; + + private String portName; + + private String username; + + private String password; + + private String endpointAddress; + + private boolean maintainSession; + + private boolean useSoapAction; + + private String soapActionUri; + + private Map customProperties; + + private Class serviceInterface; + + private boolean lookupServiceOnStartup = true; + + private QName portQName; + + private Object portStub; + + private final Object preparationMonitor = new Object(); + + + /** + * Set a reference to an existing JAX-WS Service instance, + * for example obtained via {@link org.springframework.jndi.JndiObjectFactoryBean}. + * If not set, {@link LocalJaxWsServiceFactory}'s properties have to be specified. + * @see #setWsdlDocumentUrl + * @see #setNamespaceUri + * @see #setServiceName + * @see org.springframework.jndi.JndiObjectFactoryBean + */ + public void setJaxWsService(Service jaxWsService) { + this.jaxWsService = jaxWsService; + } + + /** + * Return a reference to an existing JAX-WS Service instance, if any. + */ + public Service getJaxWsService() { + return this.jaxWsService; + } + + /** + * Set the name of the port. + * Corresponds to the "wsdl:port" name. + */ + public void setPortName(String portName) { + this.portName = portName; + } + + /** + * Return the name of the port. + */ + public String getPortName() { + return this.portName; + } + + /** + * Set the username to specify on the stub. + * @see javax.xml.ws.BindingProvider#USERNAME_PROPERTY + */ + public void setUsername(String username) { + this.username = username; + } + + /** + * Return the username to specify on the stub. + */ + public String getUsername() { + return this.username; + } + + /** + * Set the password to specify on the stub. + * @see javax.xml.ws.BindingProvider#PASSWORD_PROPERTY + */ + public void setPassword(String password) { + this.password = password; + } + + /** + * Return the password to specify on the stub. + */ + public String getPassword() { + return this.password; + } + + /** + * Set the endpoint address to specify on the stub. + * @see javax.xml.ws.BindingProvider#ENDPOINT_ADDRESS_PROPERTY + */ + public void setEndpointAddress(String endpointAddress) { + this.endpointAddress = endpointAddress; + } + + /** + * Return the endpoint address to specify on the stub. + */ + public String getEndpointAddress() { + return this.endpointAddress; + } + + /** + * Set the "session.maintain" flag to specify on the stub. + * @see javax.xml.ws.BindingProvider#SESSION_MAINTAIN_PROPERTY + */ + public void setMaintainSession(boolean maintainSession) { + this.maintainSession = maintainSession; + } + + /** + * Return the "session.maintain" flag to specify on the stub. + */ + public boolean isMaintainSession() { + return this.maintainSession; + } + + /** + * Set the "soapaction.use" flag to specify on the stub. + * @see javax.xml.ws.BindingProvider#SOAPACTION_USE_PROPERTY + */ + public void setUseSoapAction(boolean useSoapAction) { + this.useSoapAction = useSoapAction; + } + + /** + * Return the "soapaction.use" flag to specify on the stub. + */ + public boolean isUseSoapAction() { + return this.useSoapAction; + } + + /** + * Set the SOAP action URI to specify on the stub. + * @see javax.xml.ws.BindingProvider#SOAPACTION_URI_PROPERTY + */ + public void setSoapActionUri(String soapActionUri) { + this.soapActionUri = soapActionUri; + } + + /** + * Return the SOAP action URI to specify on the stub. + */ + public String getSoapActionUri() { + return this.soapActionUri; + } + + /** + * Set custom properties to be set on the stub. + *

Can be populated with a String "value" (parsed via PropertiesEditor) + * or a "props" element in XML bean definitions. + * @see javax.xml.ws.BindingProvider#getRequestContext() + */ + public void setCustomProperties(Map customProperties) { + this.customProperties = customProperties; + } + + /** + * Allow Map access to the custom properties to be set on the stub, + * with the option to add or override specific entries. + *

Useful for specifying entries directly, for example via + * "customProperties[myKey]". This is particularly useful for + * adding or overriding entries in child bean definitions. + */ + public Map getCustomProperties() { + if (this.customProperties == null) { + this.customProperties = new HashMap(); + } + return this.customProperties; + } + + /** + * Add a custom property to this JAX-WS BindingProvider. + * @param name the name of the attribute to expose + * @param value the attribute value to expose + * @see javax.xml.ws.BindingProvider#getRequestContext() + */ + public void addCustomProperty(String name, Object value) { + getCustomProperties().put(name, value); + } + + /** + * Set the interface of the service that this factory should create a proxy for. + */ + public void setServiceInterface(Class serviceInterface) { + if (serviceInterface != null && !serviceInterface.isInterface()) { + throw new IllegalArgumentException("'serviceInterface' must be an interface"); + } + this.serviceInterface = serviceInterface; + } + + /** + * Return the interface of the service that this factory should create a proxy for. + */ + public Class getServiceInterface() { + return this.serviceInterface; + } + + /** + * Set whether to look up the JAX-WS service on startup. + *

Default is "true". Turn this flag off to allow for late start + * of the target server. In this case, the JAX-WS service will be + * lazily fetched on first access. + */ + public void setLookupServiceOnStartup(boolean lookupServiceOnStartup) { + this.lookupServiceOnStartup = lookupServiceOnStartup; + } + + + public void afterPropertiesSet() { + if (this.lookupServiceOnStartup) { + prepare(); + } + } + + public void prepare() { + if (getServiceInterface() == null) { + throw new IllegalArgumentException("Property 'serviceInterface' is required"); + } + Service serviceToUse = getJaxWsService(); + if (serviceToUse == null) { + serviceToUse = createJaxWsService(); + } + this.portQName = getQName(getPortName() != null ? getPortName() : getServiceInterface().getName()); + Object stub = (getPortName() != null ? + serviceToUse.getPort(this.portQName, getServiceInterface()) : serviceToUse.getPort(getServiceInterface())); + preparePortStub(stub); + this.portStub = stub; + } + + /** + * Return whether this client interceptor has already been prepared, + * i.e. has already looked up the JAX-WS service and port. + */ + protected boolean isPrepared() { + synchronized (this.preparationMonitor) { + return (this.portStub != null); + } + } + + /** + * Return the prepared QName for the port. + * @see #setPortName + * @see #getQName + */ + protected final QName getPortQName() { + return this.portQName; + } + + /** + * Prepare the given JAX-WS port stub, applying properties to it. + * Called by {@link #prepare}. + * @param stub the current JAX-WS port stub + * @see #setUsername + * @see #setPassword + * @see #setEndpointAddress + * @see #setMaintainSession + * @see #setCustomProperties + */ + protected void preparePortStub(Object stub) { + Map stubProperties = new HashMap(); + String username = getUsername(); + if (username != null) { + stubProperties.put(BindingProvider.USERNAME_PROPERTY, username); + } + String password = getPassword(); + if (password != null) { + stubProperties.put(BindingProvider.PASSWORD_PROPERTY, password); + } + String endpointAddress = getEndpointAddress(); + if (endpointAddress != null) { + stubProperties.put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, endpointAddress); + } + if (isMaintainSession()) { + stubProperties.put(BindingProvider.SESSION_MAINTAIN_PROPERTY, Boolean.TRUE); + } + if (isUseSoapAction()) { + stubProperties.put(BindingProvider.SOAPACTION_USE_PROPERTY, Boolean.TRUE); + } + String soapActionUri = getSoapActionUri(); + if (soapActionUri != null) { + stubProperties.put(BindingProvider.SOAPACTION_URI_PROPERTY, soapActionUri); + } + stubProperties.putAll(getCustomProperties()); + if (!stubProperties.isEmpty()) { + if (!(stub instanceof BindingProvider)) { + throw new RemoteLookupFailureException("Port stub of class [" + stub.getClass().getName() + + "] is not a customizable JAX-WS stub: it does not implement interface [javax.xml.ws.BindingProvider]"); + } + ((BindingProvider) stub).getRequestContext().putAll(stubProperties); + } + } + + /** + * Return the underlying JAX-WS port stub that this interceptor delegates to + * for each method invocation on the proxy. + */ + protected Object getPortStub() { + return this.portStub; + } + + + public Object invoke(MethodInvocation invocation) throws Throwable { + if (AopUtils.isToStringMethod(invocation.getMethod())) { + return "JAX-WS proxy for port [" + getPortName() + "] of service [" + getServiceName() + "]"; + } + // Lazily prepare service and stub if necessary. + synchronized (this.preparationMonitor) { + if (!isPrepared()) { + prepare(); + } + } + return doInvoke(invocation); + } + + /** + * Perform a JAX-WS service invocation based on the given method invocation. + * @param invocation the AOP method invocation + * @return the invocation result, if any + * @throws Throwable in case of invocation failure + * @see #getPortStub() + * @see #doInvoke(org.aopalliance.intercept.MethodInvocation, Object) + */ + protected Object doInvoke(MethodInvocation invocation) throws Throwable { + try { + return doInvoke(invocation, getPortStub()); + } + catch (SOAPFaultException ex) { + throw new JaxWsSoapFaultException(ex); + } + catch (ProtocolException ex) { + throw new RemoteConnectFailureException("Could not connect to remote service [" + this.portQName + "]", ex); + } + catch (WebServiceException ex) { + throw new RemoteAccessException("Could not access remote service at [" + this.portQName + "]", ex); + } + } + + /** + * Perform a JAX-WS service invocation on the given port stub. + * @param invocation the AOP method invocation + * @param portStub the RMI port stub to invoke + * @return the invocation result, if any + * @throws Throwable in case of invocation failure + * @see #getPortStub() + */ + protected Object doInvoke(MethodInvocation invocation, Object portStub) throws Throwable { + Method method = invocation.getMethod(); + try { + return method.invoke(portStub, invocation.getArguments()); + } + catch (InvocationTargetException ex) { + throw ex.getTargetException(); + } + catch (Throwable ex) { + throw new RemoteProxyFailureException("Invocation of stub method failed: " + method, ex); + } + } + +} Index: 3rdParty_sources/spring/org/springframework/remoting/jaxws/JaxWsPortProxyFactoryBean.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/remoting/jaxws/JaxWsPortProxyFactoryBean.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/remoting/jaxws/JaxWsPortProxyFactoryBean.java 17 Aug 2012 15:16:06 -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.remoting.jaxws; + +import javax.xml.ws.BindingProvider; + +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} for a specific port of a + * JAX-WS service. Exposes a proxy for the port, to be used for bean references. + * Inherits configuration properties from {@link JaxWsPortClientInterceptor}. + * + * @author Juergen Hoeller + * @since 2.5 + * @see #setServiceInterface + * @see LocalJaxWsServiceFactoryBean + */ +public class JaxWsPortProxyFactoryBean extends JaxWsPortClientInterceptor + implements FactoryBean, BeanClassLoaderAware { + + private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader(); + + private Object serviceProxy; + + + public void setBeanClassLoader(ClassLoader classLoader) { + this.beanClassLoader = classLoader; + } + + public void afterPropertiesSet() { + super.afterPropertiesSet(); + + // Build a proxy that also exposes the JAX-WS BindingProvider interface. + ProxyFactory pf = new ProxyFactory(); + pf.addInterface(getServiceInterface()); + pf.addInterface(BindingProvider.class); + pf.addAdvice(this); + this.serviceProxy = pf.getProxy(this.beanClassLoader); + } + + + public Object getObject() { + return this.serviceProxy; + } + + public Class getObjectType() { + return getServiceInterface(); + } + + public boolean isSingleton() { + return true; + } + +} Index: 3rdParty_sources/spring/org/springframework/remoting/jaxws/JaxWsSoapFaultException.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/remoting/jaxws/JaxWsSoapFaultException.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/remoting/jaxws/JaxWsSoapFaultException.java 17 Aug 2012 15:16:06 -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.remoting.jaxws; + +import javax.xml.namespace.QName; +import javax.xml.soap.SOAPFault; +import javax.xml.ws.soap.SOAPFaultException; + +import org.springframework.remoting.soap.SoapFaultException; + +/** + * Spring SoapFaultException adapter for the JAX-WS + * {@link javax.xml.ws.soap.SOAPFaultException} class. + * + * @author Juergen Hoeller + * @since 2.5 + */ +public class JaxWsSoapFaultException extends SoapFaultException { + + /** + * Constructor for JaxWsSoapFaultException. + * @param original the original JAX-WS SOAPFaultException to wrap + */ + public JaxWsSoapFaultException(SOAPFaultException original) { + super(original.getMessage(), original); + } + + /** + * Return the wrapped JAX-WS SOAPFault. + */ + public final SOAPFault getFault() { + return ((SOAPFaultException) getCause()).getFault(); + } + + + public String getFaultCode() { + return getFault().getFaultCode(); + } + + public QName getFaultCodeAsQName() { + return getFault().getFaultCodeAsQName(); + } + + public String getFaultString() { + return getFault().getFaultString(); + } + + public String getFaultActor() { + return getFault().getFaultActor(); + } + +} Index: 3rdParty_sources/spring/org/springframework/remoting/jaxws/LocalJaxWsServiceFactory.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/remoting/jaxws/LocalJaxWsServiceFactory.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/remoting/jaxws/LocalJaxWsServiceFactory.java 17 Aug 2012 15:16:07 -0000 1.1 @@ -0,0 +1,156 @@ +/* + * 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.remoting.jaxws; + +import java.net.URL; +import java.util.concurrent.Executor; + +import javax.xml.namespace.QName; +import javax.xml.ws.Service; +import javax.xml.ws.handler.HandlerResolver; + +import org.springframework.core.task.TaskExecutor; +import org.springframework.core.task.support.ConcurrentExecutorAdapter; + +/** + * Factory for locally defined JAX-WS {@link javax.xml.ws.Service} references. + * Uses the JAX-WS {@link javax.xml.ws.Service#create} factory API underneath. + * + *

Serves as base class for {@link LocalJaxWsServiceFactoryBean} as well as + * {@link JaxWsPortClientInterceptor} and {@link JaxWsPortProxyFactoryBean}. + * + * @author Juergen Hoeller + * @since 2.5 + * @see javax.xml.ws.Service + * @see LocalJaxWsServiceFactoryBean + * @see JaxWsPortClientInterceptor + * @see JaxWsPortProxyFactoryBean + */ +public class LocalJaxWsServiceFactory { + + private URL wsdlDocumentUrl; + + private String namespaceUri; + + private String serviceName; + + private Executor executor; + + private HandlerResolver handlerResolver; + + + /** + * Set the URL of the WSDL document that describes the service. + */ + public void setWsdlDocumentUrl(URL wsdlDocumentUrl) { + this.wsdlDocumentUrl = wsdlDocumentUrl; + } + + /** + * Return the URL of the WSDL document that describes the service. + */ + public URL getWsdlDocumentUrl() { + return this.wsdlDocumentUrl; + } + + /** + * Set the namespace URI of the service. + * Corresponds to the WSDL "targetNamespace". + */ + public void setNamespaceUri(String namespaceUri) { + this.namespaceUri = (namespaceUri != null ? namespaceUri.trim() : null); + } + + /** + * Return the namespace URI of the service. + */ + public String getNamespaceUri() { + return this.namespaceUri; + } + + /** + * Set the name of the service to look up. + * Corresponds to the "wsdl:service" name. + */ + public void setServiceName(String serviceName) { + this.serviceName = serviceName; + } + + /** + * Return the name of the service. + */ + public String getServiceName() { + return this.serviceName; + } + + /** + * Set the JDK concurrent executor to use for asynchronous executions + * that require callbacks. + * @see javax.xml.ws.Service#setExecutor + */ + public void setExecutor(Executor executor) { + this.executor = executor; + } + + /** + * Set the Spring TaskExecutor to use for asynchronous executions + * that require callbacks. + * @see javax.xml.ws.Service#setExecutor + */ + public void setTaskExecutor(TaskExecutor executor) { + this.executor = new ConcurrentExecutorAdapter(executor); + } + + /** + * Set the JAX-WS HandlerResolver to use for all proxies and dispatchers + * created through this factory. + * @see javax.xml.ws.Service#setHandlerResolver + */ + public void setHandlerResolver(HandlerResolver handlerResolver) { + this.handlerResolver = handlerResolver; + } + + + /** + * Create a JAX-WS Service according to the parameters of this factory. + * @see #setServiceName + * @see #setWsdlDocumentUrl + */ + public Service createJaxWsService() { + Service service = (this.wsdlDocumentUrl != null ? + Service.create(this.wsdlDocumentUrl, getQName(this.serviceName)) : + Service.create(getQName(this.serviceName))); + + if (this.executor != null) { + service.setExecutor(this.executor); + } + if (this.handlerResolver != null) { + service.setHandlerResolver(this.handlerResolver); + } + return service; + } + + /** + * Return a QName for the given name, relative to the namespace URI + * of this factory, if given. + * @see #setNamespaceUri + */ + protected QName getQName(String name) { + return (getNamespaceUri() != null ? new QName(getNamespaceUri(), name) : new QName(name)); + } + +} Index: 3rdParty_sources/spring/org/springframework/remoting/jaxws/LocalJaxWsServiceFactoryBean.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/remoting/jaxws/LocalJaxWsServiceFactoryBean.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/remoting/jaxws/LocalJaxWsServiceFactoryBean.java 17 Aug 2012 15:16:07 -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.remoting.jaxws; + +import javax.xml.ws.Service; + +import org.springframework.beans.factory.FactoryBean; +import org.springframework.beans.factory.InitializingBean; + +/** + * {@link org.springframework.beans.factory.FactoryBean} for locally + * defined JAX-WS Service references. + * Uses {@link LocalJaxWsServiceFactory}'s facilities underneath. + * + *

Alternatively, JAX-WS Service references can be looked up + * in the JNDI environment of the J2EE container. + * + * @author Juergen Hoeller + * @since 2.5 + * @see javax.xml.ws.Service + * @see org.springframework.jndi.JndiObjectFactoryBean + * @see JaxWsPortProxyFactoryBean + */ +public class LocalJaxWsServiceFactoryBean extends LocalJaxWsServiceFactory implements FactoryBean, InitializingBean { + + private Service service; + + + public void afterPropertiesSet() { + this.service = createJaxWsService(); + } + + public Object getObject() throws Exception { + return this.service; + } + + public Class getObjectType() { + return (this.service != null ? this.service.getClass() : Service.class); + } + + public boolean isSingleton() { + return true; + } + +} Index: 3rdParty_sources/spring/org/springframework/remoting/jaxws/SimpleHttpServerJaxWsServiceExporter.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/remoting/jaxws/SimpleHttpServerJaxWsServiceExporter.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/remoting/jaxws/SimpleHttpServerJaxWsServiceExporter.java 17 Aug 2012 15:16:06 -0000 1.1 @@ -0,0 +1,186 @@ +/* + * 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.remoting.jaxws; + +import java.net.InetSocketAddress; +import java.util.List; + +import javax.jws.WebService; +import javax.xml.ws.Endpoint; + +import com.sun.net.httpserver.Authenticator; +import com.sun.net.httpserver.Filter; +import com.sun.net.httpserver.HttpContext; +import com.sun.net.httpserver.HttpServer; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * Simple exporter for JAX-WS services, autodetecting annotated service beans + * (through the JAX-WS {@link javax.jws.WebService} annotation) and exporting + * them through the HTTP server included in Sun's JDK 1.6. The full address + * for each service will consist of the server's base address with the + * service name appended (e.g. "http://localhost:8080/OrderService"). + * + *

Note that this exporter will only work on Sun's JDK 1.6 or higher, as well + * as on JDKs that ship Sun's entire class library as included in the Sun JDK. + * For a portable JAX-WS exporter, have a look at {@link SimpleJaxWsServiceExporter}. + * + * @author Juergen Hoeller + * @since 2.5.5 + * @see javax.jws.WebService + * @see javax.xml.ws.Endpoint#publish(Object) + * @see SimpleJaxWsServiceExporter + */ +public class SimpleHttpServerJaxWsServiceExporter extends AbstractJaxWsServiceExporter { + + protected final Log logger = LogFactory.getLog(getClass()); + + private HttpServer server; + + private int port = 8080; + + private String hostname; + + private int backlog = -1; + + private int shutdownDelay = 0; + + private String basePath = "/"; + + private List filters; + + private Authenticator authenticator; + + private boolean localServer = false; + + + /** + * Specify an existing HTTP server to register the web service contexts + * with. This will typically be a server managed by the general Spring + * {@link org.springframework.remoting.support.SimpleHttpServerFactoryBean}. + *

Alternatively, configure a local HTTP server through the + * {@link #setPort "port"}, {@link #setHostname "hostname"} and + * {@link #setBacklog "backlog"} properties (or rely on the defaults there). + */ + public void setServer(HttpServer server) { + this.server = server; + } + + /** + * Specify the HTTP server's port. Default is 8080. + *

Only applicable for a locally configured HTTP server. + * Ignored when the {@link #setServer "server"} property has been specified. + */ + public void setPort(int port) { + this.port = port; + } + + /** + * Specify the HTTP server's hostname to bind to. Default is localhost; + * can be overridden with a specific network address to bind to. + *

Only applicable for a locally configured HTTP server. + * Ignored when the {@link #setServer "server"} property has been specified. + */ + public void setHostname(String hostname) { + this.hostname = hostname; + } + + /** + * Specify the HTTP server's TCP backlog. Default is -1, + * indicating the system's default value. + *

Only applicable for a locally configured HTTP server. + * Ignored when the {@link #setServer "server"} property has been specified. + */ + public void setBacklog(int backlog) { + this.backlog = backlog; + } + + /** + * Specify the number of seconds to wait until HTTP exchanges have + * completed when shutting down the HTTP server. Default is 0. + *

Only applicable for a locally configured HTTP server. + * Ignored when the {@link #setServer "server"} property has been specified. + */ + public void setShutdownDelay(int shutdownDelay) { + this.shutdownDelay = shutdownDelay; + } + + /** + * Set the base path for context publication. Default is "/". + *

For each context publication path, the service name will be + * appended to this base address. E.g. service name "OrderService" + * -> "/OrderService". + * @see javax.xml.ws.Endpoint#publish(Object) + * @see javax.jws.WebService#serviceName() + */ + public void setBasePath(String basePath) { + this.basePath = basePath; + } + + /** + * Register common {@link com.sun.net.httpserver.Filter Filters} to be + * applied to all detected {@link javax.jws.WebService} annotated beans. + */ + public void setFilters(List filters) { + this.filters = filters; + } + + /** + * Register a common {@link com.sun.net.httpserver.Authenticator} to be + * applied to all detected {@link javax.jws.WebService} annotated beans. + */ + public void setAuthenticator(Authenticator authenticator) { + this.authenticator = authenticator; + } + + + public void afterPropertiesSet() throws Exception { + if (this.server == null) { + InetSocketAddress address = (this.hostname != null ? + new InetSocketAddress(this.hostname, this.port) : new InetSocketAddress(this.port)); + this.server = HttpServer.create(address, this.backlog); + if (this.logger.isInfoEnabled()) { + this.logger.info("Starting HttpServer at address " + address); + } + this.server.start(); + this.localServer = true; + } + super.afterPropertiesSet(); + } + + protected void publishEndpoint(Endpoint endpoint, WebService annotation) { + String fullPath = this.basePath + annotation.serviceName(); + HttpContext httpContext = this.server.createContext(fullPath); + if (this.filters != null) { + httpContext.getFilters().addAll(this.filters); + } + if (this.authenticator != null) { + httpContext.setAuthenticator(this.authenticator); + } + endpoint.publish(httpContext); + } + + public void destroy() { + super.destroy(); + if (this.localServer) { + logger.info("Stopping HttpServer"); + this.server.stop(this.shutdownDelay); + } + } + +} Index: 3rdParty_sources/spring/org/springframework/remoting/jaxws/SimpleJaxWsServiceExporter.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/remoting/jaxws/SimpleJaxWsServiceExporter.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/remoting/jaxws/SimpleJaxWsServiceExporter.java 17 Aug 2012 15:16:06 -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.remoting.jaxws; + +import javax.jws.WebService; +import javax.xml.ws.Endpoint; + +/** + * Simple exporter for JAX-WS services, autodetecting annotated service beans + * (through the JAX-WS {@link javax.jws.WebService} annotation) and exporting + * them with a configured base address (by default "http://localhost:8080/") + * using the JAX-WS provider's built-in publication support. The full address + * for each service will consist of the base address with the service name + * appended (e.g. "http://localhost:8080/OrderService"). + * + *

Note that this exporter will only work if the JAX-WS runtime actually + * supports publishing with an address argument, i.e. if the JAX-WS runtime + * ships an internal HTTP server. This is the case with the JAX-WS runtime + * that's inclued in Sun's JDK 1.6 but not with the standalone JAX-WS 2.1 RI. + * + *

For explicit configuration of JAX-WS endpoints with Sun's JDK 1.6 + * HTTP server, consider using {@link SimpleHttpServerJaxWsServiceExporter}! + * + * @author Juergen Hoeller + * @since 2.5 + * @see javax.jws.WebService + * @see javax.xml.ws.Endpoint#publish(String) + * @see SimpleHttpServerJaxWsServiceExporter + */ +public class SimpleJaxWsServiceExporter extends AbstractJaxWsServiceExporter { + + public static final String DEFAULT_BASE_ADDRESS = "http://localhost:8080/"; + + private String baseAddress = DEFAULT_BASE_ADDRESS; + + + /** + * Set the base address for exported services. + * Default is "http://localhost:8080/". + *

For each actual publication address, the service name will be + * appended to this base address. E.g. service name "OrderService" + * -> "http://localhost:8080/OrderService". + * @see javax.xml.ws.Endpoint#publish(String) + * @see javax.jws.WebService#serviceName() + */ + public void setBaseAddress(String baseAddress) { + this.baseAddress = baseAddress; + } + + + protected void publishEndpoint(Endpoint endpoint, WebService annotation) { + String fullAddress = this.baseAddress + annotation.serviceName(); + endpoint.publish(fullAddress); + } + +} Index: 3rdParty_sources/spring/org/springframework/remoting/jaxws/package.html =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/remoting/jaxws/package.html,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/remoting/jaxws/package.html 17 Aug 2012 15:16:07 -0000 1.1 @@ -0,0 +1,9 @@ + + + +Remoting classes for Web Services via JAX-WS (the successor of JAX-RPC), +as included in Java 6 and Java EE 5. This package provides proxy +factories for accessing JAX-WS services and ports. + + + Index: 3rdParty_sources/spring/org/springframework/remoting/rmi/CodebaseAwareObjectInputStream.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/remoting/rmi/CodebaseAwareObjectInputStream.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/remoting/rmi/CodebaseAwareObjectInputStream.java 17 Aug 2012 15:16:15 -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.remoting.rmi; + +import java.io.IOException; +import java.io.InputStream; +import java.rmi.server.RMIClassLoader; + +import org.springframework.core.ConfigurableObjectInputStream; + +/** + * Special ObjectInputStream subclass that falls back to a specified codebase + * to load classes from if not found locally. In contrast to standard RMI + * conventions for dynamic class download, it is the client that determines + * the codebase URL here, rather than the "java.rmi.server.codebase" system + * property on the server. + * + *

Uses the JDK's RMIClassLoader to load classes from the specified codebase. + * The codebase can consist of multiple URLs, separated by spaces. + * Note that RMIClassLoader requires a SecurityManager to be set, like when + * using dynamic class download with standard RMI! (See the RMI documentation + * for details.) + * + *

Despite residing in the RMI package, this class is not used for + * RmiClientInterceptor, which uses the standard RMI infrastructure instead + * and thus is only able to rely on RMI's standard dynamic class download via + * "java.rmi.server.codebase". CodebaseAwareObjectInputStream is used by + * HttpInvokerClientInterceptor (see the "codebaseUrl" property there). + * + *

Thanks to Lionel Mestre for suggesting the option and providing + * a prototype! + * + * @author Juergen Hoeller + * @since 1.1.3 + * @see java.rmi.server.RMIClassLoader + * @see RemoteInvocationSerializingExporter#createObjectInputStream + * @see org.springframework.remoting.httpinvoker.HttpInvokerClientInterceptor#setCodebaseUrl + */ +public class CodebaseAwareObjectInputStream extends ConfigurableObjectInputStream { + + private final String codebaseUrl; + + + /** + * Create a new CodebaseAwareObjectInputStream for the given InputStream and codebase. + * @param in the InputStream to read from + * @param codebaseUrl the codebase URL to load classes from if not found locally + * (can consist of multiple URLs, separated by spaces) + * @see java.io.ObjectInputStream#ObjectInputStream(java.io.InputStream) + */ + public CodebaseAwareObjectInputStream(InputStream in, String codebaseUrl) throws IOException { + this(in, null, codebaseUrl); + } + + /** + * Create a new CodebaseAwareObjectInputStream for the given InputStream and codebase. + * @param in the InputStream to read from + * @param classLoader the ClassLoader to use for loading local classes + * (may be null to indicate RMI's default ClassLoader) + * @param codebaseUrl the codebase URL to load classes from if not found locally + * (can consist of multiple URLs, separated by spaces) + * @see java.io.ObjectInputStream#ObjectInputStream(java.io.InputStream) + */ + public CodebaseAwareObjectInputStream( + InputStream in, ClassLoader classLoader, String codebaseUrl) throws IOException { + + super(in, classLoader); + this.codebaseUrl = codebaseUrl; + } + + + protected Class resolveFallbackIfPossible(String className, ClassNotFoundException ex) + throws IOException, ClassNotFoundException { + + // If codebaseUrl is set, try to load the class with the RMIClassLoader. + // Else, propagate the ClassNotFoundException. + if (this.codebaseUrl == null) { + throw ex; + } + return RMIClassLoader.loadClass(this.codebaseUrl, className); + } + + protected ClassLoader getFallbackClassLoader() throws IOException { + return RMIClassLoader.getClassLoader(this.codebaseUrl); + } + +} Index: 3rdParty_sources/spring/org/springframework/remoting/rmi/JndiRmiClientInterceptor.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/remoting/rmi/JndiRmiClientInterceptor.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/remoting/rmi/JndiRmiClientInterceptor.java 17 Aug 2012 15:16:15 -0000 1.1 @@ -0,0 +1,488 @@ +/* + * 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.remoting.rmi; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.rmi.RemoteException; + +import javax.naming.NamingException; +import javax.rmi.PortableRemoteObject; + +import org.aopalliance.intercept.MethodInterceptor; +import org.aopalliance.intercept.MethodInvocation; +import org.omg.CORBA.OBJECT_NOT_EXIST; +import org.omg.CORBA.SystemException; + +import org.springframework.aop.support.AopUtils; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.jndi.JndiObjectLocator; +import org.springframework.remoting.RemoteAccessException; +import org.springframework.remoting.RemoteConnectFailureException; +import org.springframework.remoting.RemoteInvocationFailureException; +import org.springframework.remoting.RemoteLookupFailureException; +import org.springframework.remoting.support.DefaultRemoteInvocationFactory; +import org.springframework.remoting.support.RemoteInvocation; +import org.springframework.remoting.support.RemoteInvocationFactory; +import org.springframework.util.ReflectionUtils; + +/** + * {@link org.aopalliance.intercept.MethodInterceptor} for accessing RMI services from JNDI. + * Typically used for RMI-IIOP (CORBA), but can also be used for EJB home objects + * (for example, a Stateful Session Bean home). In contrast to a plain JNDI lookup, + * this accessor also performs narrowing through PortableRemoteObject. + * + *

With conventional RMI services, this invoker is typically used with the RMI + * service interface. Alternatively, this invoker can also proxy a remote RMI service + * with a matching non-RMI business interface, i.e. an interface that mirrors the RMI + * service methods but does not declare RemoteExceptions. In the latter case, + * RemoteExceptions thrown by the RMI stub will automatically get converted to + * Spring's unchecked RemoteAccessException. + * + *

The JNDI environment can be specified as "jndiEnvironment" property, + * or be configured in a jndi.properties file or as system properties. + * For example: + * + *

<property name="jndiEnvironment">
+ * 	 <props>
+ *		 <prop key="java.naming.factory.initial">com.sun.jndi.cosnaming.CNCtxFactory</prop>
+ *		 <prop key="java.naming.provider.url">iiop://localhost:1050</prop>
+ *	 </props>
+ * </property>
+ * + * @author Juergen Hoeller + * @since 1.1 + * @see #setJndiTemplate + * @see #setJndiEnvironment + * @see #setJndiName + * @see JndiRmiServiceExporter + * @see JndiRmiProxyFactoryBean + * @see org.springframework.remoting.RemoteAccessException + * @see java.rmi.RemoteException + * @see java.rmi.Remote + * @see javax.rmi.PortableRemoteObject#narrow + */ +public class JndiRmiClientInterceptor extends JndiObjectLocator implements MethodInterceptor, InitializingBean { + + private Class serviceInterface; + + private RemoteInvocationFactory remoteInvocationFactory = new DefaultRemoteInvocationFactory(); + + private boolean lookupStubOnStartup = true; + + private boolean cacheStub = true; + + private boolean refreshStubOnConnectFailure = false; + + private Object cachedStub; + + private final Object stubMonitor = new Object(); + + + /** + * Set the interface of the service to access. + * The interface must be suitable for the particular service and remoting tool. + *

Typically required to be able to create a suitable service proxy, + * but can also be optional if the lookup returns a typed stub. + */ + public void setServiceInterface(Class serviceInterface) { + if (serviceInterface != null && !serviceInterface.isInterface()) { + throw new IllegalArgumentException("'serviceInterface' must be an interface"); + } + this.serviceInterface = serviceInterface; + } + + /** + * Return the interface of the service to access. + */ + public Class getServiceInterface() { + return this.serviceInterface; + } + + /** + * Set the RemoteInvocationFactory to use for this accessor. + * Default is a {@link 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; + } + + /** + * Return the RemoteInvocationFactory used by this accessor. + */ + public RemoteInvocationFactory getRemoteInvocationFactory() { + return this.remoteInvocationFactory; + } + + /** + * Set whether to look up the RMI stub on startup. Default is "true". + *

Can be turned off to allow for late start of the RMI server. + * In this case, the RMI stub will be fetched on first access. + * @see #setCacheStub + */ + public void setLookupStubOnStartup(boolean lookupStubOnStartup) { + this.lookupStubOnStartup = lookupStubOnStartup; + } + + /** + * Set whether to cache the RMI stub once it has been located. + * Default is "true". + *

Can be turned off to allow for hot restart of the RMI server. + * In this case, the RMI stub will be fetched for each invocation. + * @see #setLookupStubOnStartup + */ + public void setCacheStub(boolean cacheStub) { + this.cacheStub = cacheStub; + } + + /** + * Set whether to refresh the RMI stub on connect failure. + * Default is "false". + *

Can be turned on to allow for hot restart of the RMI server. + * If a cached RMI stub throws an RMI exception that indicates a + * remote connect failure, a fresh proxy will be fetched and the + * invocation will be retried. + * @see java.rmi.ConnectException + * @see java.rmi.ConnectIOException + * @see java.rmi.NoSuchObjectException + */ + public void setRefreshStubOnConnectFailure(boolean refreshStubOnConnectFailure) { + this.refreshStubOnConnectFailure = refreshStubOnConnectFailure; + } + + + public void afterPropertiesSet() throws NamingException { + super.afterPropertiesSet(); + prepare(); + } + + /** + * Fetches the RMI stub on startup, if necessary. + * @throws RemoteLookupFailureException if RMI stub creation failed + * @see #setLookupStubOnStartup + * @see #lookupStub + */ + public void prepare() throws RemoteLookupFailureException { + // Cache RMI stub on initialization? + if (this.lookupStubOnStartup) { + Object remoteObj = lookupStub(); + if (logger.isDebugEnabled()) { + if (remoteObj instanceof RmiInvocationHandler) { + logger.debug("JNDI RMI object [" + getJndiName() + "] is an RMI invoker"); + } + else if (getServiceInterface() != null) { + boolean isImpl = getServiceInterface().isInstance(remoteObj); + logger.debug("Using service interface [" + getServiceInterface().getName() + + "] for JNDI RMI object [" + getJndiName() + "] - " + + (!isImpl ? "not " : "") + "directly implemented"); + } + } + if (this.cacheStub) { + this.cachedStub = remoteObj; + } + } + } + + /** + * Create the RMI stub, typically by looking it up. + *

Called on interceptor initialization if "cacheStub" is "true"; + * else called for each invocation by {@link #getStub()}. + *

The default implementation retrieves the service from the + * JNDI environment. This can be overridden in subclasses. + * @return the RMI stub to store in this interceptor + * @throws RemoteLookupFailureException if RMI stub creation failed + * @see #setCacheStub + * @see #lookup + */ + protected Object lookupStub() throws RemoteLookupFailureException { + try { + Object stub = lookup(); + if (getServiceInterface() != null && !(stub instanceof RmiInvocationHandler)) { + try { + stub = PortableRemoteObject.narrow(stub, getServiceInterface()); + } + catch (ClassCastException ex) { + throw new RemoteLookupFailureException( + "Could not narrow RMI stub to service interface [" + getServiceInterface().getName() + "]", ex); + } + } + return stub; + } + catch (NamingException ex) { + throw new RemoteLookupFailureException("JNDI lookup for RMI service [" + getJndiName() + "] failed", ex); + } + } + + /** + * Return the RMI stub to use. Called for each invocation. + *

The default implementation returns the stub created on initialization, + * if any. Else, it invokes {@link #lookupStub} to get a new stub for + * each invocation. This can be overridden in subclasses, for example in + * order to cache a stub for a given amount of time before recreating it, + * or to test the stub whether it is still alive. + * @return the RMI stub to use for an invocation + * @throws NamingException if stub creation failed + * @throws RemoteLookupFailureException if RMI stub creation failed + */ + protected Object getStub() throws NamingException, RemoteLookupFailureException { + if (!this.cacheStub || (this.lookupStubOnStartup && !this.refreshStubOnConnectFailure)) { + return (this.cachedStub != null ? this.cachedStub : lookupStub()); + } + else { + synchronized (this.stubMonitor) { + if (this.cachedStub == null) { + this.cachedStub = lookupStub(); + } + return this.cachedStub; + } + } + } + + + /** + * Fetches an RMI stub and delegates to {@link #doInvoke}. + * If configured to refresh on connect failure, it will call + * {@link #refreshAndRetry} on corresponding RMI exceptions. + * @see #getStub + * @see #doInvoke + * @see #refreshAndRetry + * @see java.rmi.ConnectException + * @see java.rmi.ConnectIOException + * @see java.rmi.NoSuchObjectException + */ + public Object invoke(MethodInvocation invocation) throws Throwable { + Object stub = null; + try { + stub = getStub(); + } + catch (NamingException ex) { + throw new RemoteLookupFailureException("JNDI lookup for RMI service [" + getJndiName() + "] failed", ex); + } + try { + return doInvoke(invocation, stub); + } + catch (RemoteConnectFailureException ex) { + return handleRemoteConnectFailure(invocation, ex); + } + catch (RemoteException ex) { + if (isConnectFailure(ex)) { + return handleRemoteConnectFailure(invocation, ex); + } + else { + throw ex; + } + } + catch (SystemException ex) { + if (isConnectFailure(ex)) { + return handleRemoteConnectFailure(invocation, ex); + } + else { + throw ex; + } + } + } + + /** + * Determine whether the given RMI exception indicates a connect failure. + *

The default implementation delegates to + * {@link RmiClientInterceptorUtils#isConnectFailure}. + * @param ex the RMI exception to check + * @return whether the exception should be treated as connect failure + */ + protected boolean isConnectFailure(RemoteException ex) { + return RmiClientInterceptorUtils.isConnectFailure(ex); + } + + /** + * Determine whether the given CORBA exception indicates a connect failure. + *

The default implementation checks for CORBA's + * {@link org.omg.CORBA.OBJECT_NOT_EXIST} exception. + * @param ex the RMI exception to check + * @return whether the exception should be treated as connect failure + */ + protected boolean isConnectFailure(SystemException ex) { + return (ex instanceof OBJECT_NOT_EXIST); + } + + /** + * Refresh the stub and retry the remote invocation if necessary. + *

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 failed too. + */ + private Object handleRemoteConnectFailure(MethodInvocation invocation, Exception ex) throws Throwable { + if (this.refreshStubOnConnectFailure) { + if (logger.isDebugEnabled()) { + logger.debug("Could not connect to RMI service [" + getJndiName() + "] - retrying", ex); + } + else if (logger.isWarnEnabled()) { + logger.warn("Could not connect to RMI service [" + getJndiName() + "] - retrying"); + } + return refreshAndRetry(invocation); + } + else { + throw ex; + } + } + + /** + * Refresh the RMI stub and retry the given invocation. + * Called by invoke on connect failure. + * @param invocation the AOP method invocation + * @return the invocation result, if any + * @throws Throwable in case of invocation failure + * @see #invoke + */ + protected Object refreshAndRetry(MethodInvocation invocation) throws Throwable { + Object freshStub = null; + synchronized (this.stubMonitor) { + this.cachedStub = null; + freshStub = lookupStub(); + if (this.cacheStub) { + this.cachedStub = freshStub; + } + } + return doInvoke(invocation, freshStub); + } + + + /** + * Perform the given invocation on the given RMI stub. + * @param invocation the AOP method invocation + * @param stub the RMI stub to invoke + * @return the invocation result, if any + * @throws Throwable in case of invocation failure + */ + protected Object doInvoke(MethodInvocation invocation, Object stub) throws Throwable { + if (stub instanceof RmiInvocationHandler) { + // RMI invoker + try { + return doInvoke(invocation, (RmiInvocationHandler) stub); + } + catch (RemoteException ex) { + throw convertRmiAccessException(ex, invocation.getMethod()); + } + catch (SystemException ex) { + throw convertCorbaAccessException(ex, invocation.getMethod()); + } + catch (InvocationTargetException ex) { + throw ex.getTargetException(); + } + catch (Throwable ex) { + throw new RemoteInvocationFailureException("Invocation of method [" + invocation.getMethod() + + "] failed in RMI service [" + getJndiName() + "]", ex); + } + } + else { + // traditional RMI stub + try { + return RmiClientInterceptorUtils.invokeRemoteMethod(invocation, stub); + } + catch (InvocationTargetException ex) { + Throwable targetEx = ex.getTargetException(); + if (targetEx instanceof RemoteException) { + throw convertRmiAccessException((RemoteException) targetEx, invocation.getMethod()); + } + else if (targetEx instanceof SystemException) { + throw convertCorbaAccessException((SystemException) targetEx, invocation.getMethod()); + } + else { + throw targetEx; + } + } + } + } + + /** + * Apply the given AOP method invocation to the given {@link RmiInvocationHandler}. + *

The default implementation delegates to {@link #createRemoteInvocation}. + * @param methodInvocation the current AOP method invocation + * @param invocationHandler the RmiInvocationHandler to apply the invocation to + * @return the invocation result + * @throws RemoteException in case of communication errors + * @throws NoSuchMethodException if the method name could not be resolved + * @throws IllegalAccessException if the method could not be accessed + * @throws InvocationTargetException if the method invocation resulted in an exception + * @see org.springframework.remoting.support.RemoteInvocation + */ + protected Object doInvoke(MethodInvocation methodInvocation, RmiInvocationHandler invocationHandler) + throws RemoteException, NoSuchMethodException, IllegalAccessException, InvocationTargetException { + + if (AopUtils.isToStringMethod(methodInvocation.getMethod())) { + return "RMI invoker proxy for service URL [" + getJndiName() + "]"; + } + + return invocationHandler.invoke(createRemoteInvocation(methodInvocation)); + } + + /** + * Create a new RemoteInvocation object for the given AOP method invocation. + *

The default implementation delegates to the configured + * {@link #setRemoteInvocationFactory RemoteInvocationFactory}. + * This can be overridden in subclasses in order to provide custom RemoteInvocation + * subclasses, containing additional invocation parameters (e.g. user credentials). + *

Note that it is preferable to build a custom RemoteInvocationFactory + * as a reusable strategy, instead of overriding this method. + * @param methodInvocation the current AOP method invocation + * @return the RemoteInvocation object + * @see RemoteInvocationFactory#createRemoteInvocation + */ + protected RemoteInvocation createRemoteInvocation(MethodInvocation methodInvocation) { + return getRemoteInvocationFactory().createRemoteInvocation(methodInvocation); + } + + /** + * Convert the given RMI RemoteException that happened during remote access + * to Spring's RemoteAccessException if the method signature does not declare + * RemoteException. Else, return the original RemoteException. + * @param method the invoked method + * @param ex the RemoteException that happened + * @return the exception to be thrown to the caller + */ + private Exception convertRmiAccessException(RemoteException ex, Method method) { + return RmiClientInterceptorUtils.convertRmiAccessException(method, ex, isConnectFailure(ex), getJndiName()); + } + + /** + * Convert the given CORBA SystemException that happened during remote access + * to Spring's RemoteAccessException if the method signature does not declare + * RemoteException. Else, return the SystemException wrapped in a RemoteException. + * @param method the invoked method + * @param ex the RemoteException that happened + * @return the exception to be thrown to the caller + */ + private Exception convertCorbaAccessException(SystemException ex, Method method) { + if (ReflectionUtils.declaresException(method, RemoteException.class)) { + // A traditional RMI service: wrap CORBA exceptions in standard RemoteExceptions. + return new RemoteException("Failed to access CORBA service [" + getJndiName() + "]", ex); + } + else { + if (isConnectFailure(ex)) { + return new RemoteConnectFailureException("Could not connect to CORBA service [" + getJndiName() + "]", ex); + } + else { + return new RemoteAccessException("Could not access CORBA service [" + getJndiName() + "]", ex); + } + } + } + +} Index: 3rdParty_sources/spring/org/springframework/remoting/rmi/JndiRmiProxyFactoryBean.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/remoting/rmi/JndiRmiProxyFactoryBean.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/remoting/rmi/JndiRmiProxyFactoryBean.java 17 Aug 2012 15:16:15 -0000 1.1 @@ -0,0 +1,96 @@ +/* + * 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.remoting.rmi; + +import javax.naming.NamingException; + +import org.springframework.aop.framework.ProxyFactory; +import org.springframework.beans.factory.BeanClassLoaderAware; +import org.springframework.beans.factory.FactoryBean; +import org.springframework.util.ClassUtils; + +/** + * Factory bean for RMI proxies from JNDI. + * + *

Typically used for RMI-IIOP (CORBA), but can also be used for EJB home objects + * (for example, a Stateful Session Bean home). In contrast to a plain JNDI lookup, + * this accessor also performs narrowing through {@link javax.rmi.PortableRemoteObject}. + * + *

With conventional RMI services, this invoker is typically used with the RMI + * service interface. Alternatively, this invoker can also proxy a remote RMI service + * with a matching non-RMI business interface, i.e. an interface that mirrors the RMI + * service methods but does not declare RemoteExceptions. In the latter case, + * RemoteExceptions thrown by the RMI stub will automatically get converted to + * Spring's unchecked RemoteAccessException. + * + *

The JNDI environment can be specified as "jndiEnvironment" property, + * or be configured in a jndi.properties file or as system properties. + * For example: + * + *

<property name="jndiEnvironment">
+ * 	 <props>
+ *		 <prop key="java.naming.factory.initial">com.sun.jndi.cosnaming.CNCtxFactory</prop>
+ *		 <prop key="java.naming.provider.url">iiop://localhost:1050</prop>
+ *	 </props>
+ * </property>
+ * + * @author Juergen Hoeller + * @since 1.1 + * @see #setServiceInterface + * @see #setJndiName + * @see #setJndiTemplate + * @see #setJndiEnvironment + * @see #setJndiName + * @see JndiRmiServiceExporter + * @see org.springframework.remoting.RemoteAccessException + * @see java.rmi.RemoteException + * @see java.rmi.Remote + * @see javax.rmi.PortableRemoteObject#narrow + */ +public class JndiRmiProxyFactoryBean extends JndiRmiClientInterceptor implements FactoryBean, BeanClassLoaderAware { + + private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader(); + + private Object serviceProxy; + + + public void setBeanClassLoader(ClassLoader classLoader) { + this.beanClassLoader = classLoader; + } + + public void afterPropertiesSet() throws NamingException { + super.afterPropertiesSet(); + if (getServiceInterface() == null) { + throw new IllegalArgumentException("Property 'serviceInterface' is required"); + } + this.serviceProxy = new ProxyFactory(getServiceInterface(), this).getProxy(this.beanClassLoader); + } + + + public Object getObject() { + return this.serviceProxy; + } + + public Class getObjectType() { + return getServiceInterface(); + } + + public boolean isSingleton() { + return true; + } + +} Index: 3rdParty_sources/spring/org/springframework/remoting/rmi/JndiRmiServiceExporter.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/remoting/rmi/JndiRmiServiceExporter.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/remoting/rmi/JndiRmiServiceExporter.java 17 Aug 2012 15:16:15 -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.remoting.rmi; + +import java.rmi.NoSuchObjectException; +import java.rmi.Remote; +import java.rmi.RemoteException; +import java.util.Properties; + +import javax.naming.NamingException; +import javax.rmi.PortableRemoteObject; + +import org.springframework.beans.factory.DisposableBean; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.jndi.JndiTemplate; + +/** + * Service exporter which binds RMI services to JNDI. + * Typically used for RMI-IIOP (CORBA). + * + *

Exports services via the {@link javax.rmi.PortableRemoteObject} class. + * You need to run "rmic" with the "-iiop" option to generate corresponding + * stubs and skeletons for each exported service. + * + *

Also supports exposing any non-RMI service via RMI invokers, to be accessed + * via {@link JndiRmiClientInterceptor} / {@link JndiRmiProxyFactoryBean}'s + * automatic detection of such invokers. + * + *

With an RMI invoker, RMI communication works on the {@link RmiInvocationHandler} + * level, needing only one stub for any service. Service interfaces do not have to + * extend java.rmi.Remote or throw java.rmi.RemoteException + * on all methods, but in and out parameters have to be serializable. + * + *

The JNDI environment can be specified as "jndiEnvironment" bean property, + * or be configured in a jndi.properties file or as system properties. + * For example: + * + *

<property name="jndiEnvironment">
+ * 	 <props>
+ *		 <prop key="java.naming.factory.initial">com.sun.jndi.cosnaming.CNCtxFactory</prop>
+ *		 <prop key="java.naming.provider.url">iiop://localhost:1050</prop>
+ *	 </props>
+ * </property>
+ * + * @author Juergen Hoeller + * @since 1.1 + * @see #setService + * @see #setJndiTemplate + * @see #setJndiEnvironment + * @see #setJndiName + * @see JndiRmiClientInterceptor + * @see JndiRmiProxyFactoryBean + * @see javax.rmi.PortableRemoteObject#exportObject + */ +public class JndiRmiServiceExporter extends RmiBasedExporter implements InitializingBean, DisposableBean { + + private JndiTemplate jndiTemplate = new JndiTemplate(); + + private String jndiName; + + private Remote exportedObject; + + + /** + * 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()); + } + + /** + * 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); + } + + /** + * Set the JNDI name of the exported RMI service. + */ + public void setJndiName(String jndiName) { + this.jndiName = jndiName; + } + + + public void afterPropertiesSet() throws NamingException, RemoteException { + prepare(); + } + + /** + * Initialize this service exporter, binding the specified service to JNDI. + * @throws NamingException if service binding failed + * @throws RemoteException if service export failed + */ + public void prepare() throws NamingException, RemoteException { + if (this.jndiName == null) { + throw new IllegalArgumentException("Property 'jndiName' is required"); + } + + // Initialize and cache exported object. + this.exportedObject = getObjectToExport(); + PortableRemoteObject.exportObject(this.exportedObject); + + rebind(); + } + + /** + * Rebind the specified service to JNDI, for recovering in case + * of the target registry having been restarted. + * @throws NamingException if service binding failed + */ + public void rebind() throws NamingException { + if (logger.isInfoEnabled()) { + logger.info("Binding RMI service to JNDI location [" + this.jndiName + "]"); + } + this.jndiTemplate.rebind(this.jndiName, this.exportedObject); + } + + /** + * Unbind the RMI service from JNDI on bean factory shutdown. + */ + public void destroy() throws NamingException, NoSuchObjectException { + if (logger.isInfoEnabled()) { + logger.info("Unbinding RMI service from JNDI location [" + this.jndiName + "]"); + } + this.jndiTemplate.unbind(this.jndiName); + PortableRemoteObject.unexportObject(this.exportedObject); + } + +} Index: 3rdParty_sources/spring/org/springframework/remoting/rmi/RemoteInvocationSerializingExporter.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/remoting/rmi/RemoteInvocationSerializingExporter.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/remoting/rmi/RemoteInvocationSerializingExporter.java 17 Aug 2012 15:16:15 -0000 1.1 @@ -0,0 +1,161 @@ +/* + * 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.remoting.rmi; + +import java.io.IOException; +import java.io.InputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.OutputStream; +import java.rmi.RemoteException; + +import org.springframework.beans.factory.InitializingBean; +import org.springframework.remoting.support.RemoteInvocation; +import org.springframework.remoting.support.RemoteInvocationBasedExporter; +import org.springframework.remoting.support.RemoteInvocationResult; +import org.springframework.util.Assert; +import org.springframework.util.ClassUtils; + +/** + * Abstract base class for remote service exporters that explicitly deserialize + * {@link org.springframework.remoting.support.RemoteInvocation} objects and serialize + * {@link org.springframework.remoting.support.RemoteInvocationResult} objects, + * for example Spring's HTTP invoker. + * + *

Provides template methods for ObjectInputStream and + * ObjectOutputStream handling. + * + * @author Juergen Hoeller + * @since 2.5.1 + * @see java.io.ObjectInputStream + * @see java.io.ObjectOutputStream + * @see #doReadRemoteInvocation + * @see #doWriteRemoteInvocationResult + */ +public abstract class RemoteInvocationSerializingExporter extends RemoteInvocationBasedExporter + implements InitializingBean { + + /** + * Default content type: "application/x-java-serialized-object" + */ + public static final String CONTENT_TYPE_SERIALIZED_OBJECT = "application/x-java-serialized-object"; + + + private String contentType = CONTENT_TYPE_SERIALIZED_OBJECT; + + private Object proxy; + + + /** + * Specify the content type to use for sending remote invocation responses. + *

Default is "application/x-java-serialized-object". + */ + public void setContentType(String contentType) { + Assert.notNull(contentType, "'contentType' must not be null"); + this.contentType = contentType; + } + + /** + * Return the content type to use for sending remote invocation responses. + */ + public String getContentType() { + return this.contentType; + } + + + public void afterPropertiesSet() { + prepare(); + } + + /** + * Initialize this service exporter. + */ + public void prepare() { + this.proxy = getProxyForService(); + } + + protected final Object getProxy() { + Assert.notNull(this.proxy, ClassUtils.getShortName(getClass()) + " has not been initialized"); + return this.proxy; + } + + + /** + * Create an ObjectInputStream for the given InputStream. + *

The default implementation creates a Spring {@link CodebaseAwareObjectInputStream}. + * @param is the InputStream to read from + * @return the new ObjectInputStream instance to use + * @throws java.io.IOException if creation of the ObjectInputStream failed + */ + protected ObjectInputStream createObjectInputStream(InputStream is) throws IOException { + return new CodebaseAwareObjectInputStream(is, getBeanClassLoader(), null); + } + + /** + * Perform the actual reading of an invocation result object from the + * given ObjectInputStream. + *

The default implementation simply calls + * {@link java.io.ObjectInputStream#readObject()}. + * Can be overridden for deserialization of a custom wrapper object rather + * than the plain invocation, for example an encryption-aware holder. + * @param ois the ObjectInputStream to read from + * @return the RemoteInvocationResult object + * @throws java.io.IOException in case of I/O failure + * @throws ClassNotFoundException if case of a transferred class not + * being found in the local ClassLoader + */ + protected RemoteInvocation doReadRemoteInvocation(ObjectInputStream ois) + throws IOException, ClassNotFoundException { + + Object obj = ois.readObject(); + if (!(obj instanceof RemoteInvocation)) { + throw new RemoteException("Deserialized object needs to be assignable to type [" + + RemoteInvocation.class.getName() + "]: " + obj); + } + return (RemoteInvocation) obj; + } + + /** + * Create an ObjectOutputStream for the given OutputStream. + *

The default implementation creates a plain + * {@link java.io.ObjectOutputStream}. + * @param os the OutputStream to write to + * @return the new ObjectOutputStream instance to use + * @throws java.io.IOException if creation of the ObjectOutputStream failed + */ + protected ObjectOutputStream createObjectOutputStream(OutputStream os) throws IOException { + return new ObjectOutputStream(os); + } + + /** + * Perform the actual writing of the given invocation result object + * to the given ObjectOutputStream. + *

The default implementation simply calls + * {@link java.io.ObjectOutputStream#writeObject}. + * Can be overridden for serialization of a custom wrapper object rather + * than the plain invocation, for example an encryption-aware holder. + * @param result the RemoteInvocationResult object + * @param oos the ObjectOutputStream to write to + * @throws java.io.IOException if thrown by I/O methods + */ + protected void doWriteRemoteInvocationResult(RemoteInvocationResult result, ObjectOutputStream oos) + throws IOException { + + oos.writeObject(result); + } + +} Index: 3rdParty_sources/spring/org/springframework/remoting/rmi/RmiBasedExporter.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/remoting/rmi/RmiBasedExporter.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/remoting/rmi/RmiBasedExporter.java 17 Aug 2012 15:16:15 -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.remoting.rmi; + +import java.lang.reflect.InvocationTargetException; +import java.rmi.Remote; + +import org.springframework.remoting.support.RemoteInvocation; +import org.springframework.remoting.support.RemoteInvocationBasedExporter; + +/** + * Convenient superclass for RMI-based remote exporters. Provides a facility + * to automatically wrap a given plain Java service object with an + * RmiInvocationWrapper, exposing the {@link RmiInvocationHandler} remote interface. + * + *

Using the RMI invoker mechanism, RMI communication operates at the {@link RmiInvocationHandler} + * level, sharing a common invoker stub for any number of services. Service interfaces are not + * required to extend java.rmi.Remote or declare java.rmi.RemoteException + * on all service methods. However, in and out parameters still have to be serializable. + * + * @author Juergen Hoeller + * @since 1.2.5 + * @see RmiServiceExporter + * @see JndiRmiServiceExporter + */ +public abstract class RmiBasedExporter extends RemoteInvocationBasedExporter { + + /** + * Determine the object to export: either the service object itself + * or a RmiInvocationWrapper in case of a non-RMI service object. + * @return the RMI object to export + * @see #setService + * @see #setServiceInterface + */ + protected Remote getObjectToExport() { + // determine remote object + if (getService() instanceof Remote && + (getServiceInterface() == null || Remote.class.isAssignableFrom(getServiceInterface()))) { + // conventional RMI service + return (Remote) getService(); + } + else { + // RMI invoker + if (logger.isDebugEnabled()) { + logger.debug("RMI service [" + getService() + "] is an RMI invoker"); + } + return new RmiInvocationWrapper(getProxyForService(), this); + } + } + + /** + * Redefined here to be visible to RmiInvocationWrapper. + * Simply delegates to the corresponding superclass method. + */ + protected Object invoke(RemoteInvocation invocation, Object targetObject) + throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { + + return super.invoke(invocation, targetObject); + } + +} Index: 3rdParty_sources/spring/org/springframework/remoting/rmi/RmiClientInterceptor.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/remoting/rmi/RmiClientInterceptor.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/remoting/rmi/RmiClientInterceptor.java 17 Aug 2012 15:16:15 -0000 1.1 @@ -0,0 +1,413 @@ +/* + * 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.remoting.rmi; + +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLConnection; +import java.net.URLStreamHandler; +import java.rmi.Naming; +import java.rmi.NotBoundException; +import java.rmi.Remote; +import java.rmi.RemoteException; +import java.rmi.registry.LocateRegistry; +import java.rmi.registry.Registry; +import java.rmi.server.RMIClientSocketFactory; + +import org.aopalliance.intercept.MethodInterceptor; +import org.aopalliance.intercept.MethodInvocation; + +import org.springframework.aop.support.AopUtils; +import org.springframework.remoting.RemoteConnectFailureException; +import org.springframework.remoting.RemoteInvocationFailureException; +import org.springframework.remoting.RemoteLookupFailureException; +import org.springframework.remoting.support.RemoteInvocationBasedAccessor; +import org.springframework.remoting.support.RemoteInvocationUtils; + +/** + * {@link org.aopalliance.intercept.MethodInterceptor} for accessing conventional + * RMI services or RMI invokers. The service URL must be a valid RMI URL + * (e.g. "rmi://localhost:1099/myservice"). + * + *

RMI invokers work at the RmiInvocationHandler level, needing only one stub for + * any service. Service interfaces do not have to extend java.rmi.Remote + * or throw java.rmi.RemoteException. Spring's unchecked + * RemoteAccessException will be thrown on remote invocation failure. + * Of course, in and out parameters have to be serializable. + * + *

With conventional RMI services, this invoker is typically used with the RMI + * service interface. Alternatively, this invoker can also proxy a remote RMI service + * with a matching non-RMI business interface, i.e. an interface that mirrors the RMI + * service methods but does not declare RemoteExceptions. In the latter case, + * RemoteExceptions thrown by the RMI stub will automatically get converted to + * Spring's unchecked RemoteAccessException. + * + * @author Juergen Hoeller + * @since 29.09.2003 + * @see RmiServiceExporter + * @see RmiProxyFactoryBean + * @see RmiInvocationHandler + * @see org.springframework.remoting.RemoteAccessException + * @see java.rmi.RemoteException + * @see java.rmi.Remote + */ +public class RmiClientInterceptor extends RemoteInvocationBasedAccessor + implements MethodInterceptor { + + private boolean lookupStubOnStartup = true; + + private boolean cacheStub = true; + + private boolean refreshStubOnConnectFailure = false; + + private RMIClientSocketFactory registryClientSocketFactory; + + private Remote cachedStub; + + private final Object stubMonitor = new Object(); + + + /** + * Set whether to look up the RMI stub on startup. Default is "true". + *

Can be turned off to allow for late start of the RMI server. + * In this case, the RMI stub will be fetched on first access. + * @see #setCacheStub + */ + public void setLookupStubOnStartup(boolean lookupStubOnStartup) { + this.lookupStubOnStartup = lookupStubOnStartup; + } + + /** + * Set whether to cache the RMI stub once it has been located. + * Default is "true". + *

Can be turned off to allow for hot restart of the RMI server. + * In this case, the RMI stub will be fetched for each invocation. + * @see #setLookupStubOnStartup + */ + public void setCacheStub(boolean cacheStub) { + this.cacheStub = cacheStub; + } + + /** + * Set whether to refresh the RMI stub on connect failure. + * Default is "false". + *

Can be turned on to allow for hot restart of the RMI server. + * If a cached RMI stub throws an RMI exception that indicates a + * remote connect failure, a fresh proxy will be fetched and the + * invocation will be retried. + * @see java.rmi.ConnectException + * @see java.rmi.ConnectIOException + * @see java.rmi.NoSuchObjectException + */ + public void setRefreshStubOnConnectFailure(boolean refreshStubOnConnectFailure) { + this.refreshStubOnConnectFailure = refreshStubOnConnectFailure; + } + + /** + * Set a custom RMI client socket factory to use for accessing the RMI registry. + * @see java.rmi.server.RMIClientSocketFactory + * @see java.rmi.registry.LocateRegistry#getRegistry(String, int, RMIClientSocketFactory) + */ + public void setRegistryClientSocketFactory(RMIClientSocketFactory registryClientSocketFactory) { + this.registryClientSocketFactory = registryClientSocketFactory; + } + + + public void afterPropertiesSet() { + super.afterPropertiesSet(); + prepare(); + } + + /** + * Fetches RMI stub on startup, if necessary. + * @throws RemoteLookupFailureException if RMI stub creation failed + * @see #setLookupStubOnStartup + * @see #lookupStub + */ + public void prepare() throws RemoteLookupFailureException { + // Cache RMI stub on initialization? + if (this.lookupStubOnStartup) { + Remote remoteObj = lookupStub(); + if (logger.isDebugEnabled()) { + if (remoteObj instanceof RmiInvocationHandler) { + logger.debug("RMI stub [" + getServiceUrl() + "] is an RMI invoker"); + } + else if (getServiceInterface() != null) { + boolean isImpl = getServiceInterface().isInstance(remoteObj); + logger.debug("Using service interface [" + getServiceInterface().getName() + + "] for RMI stub [" + getServiceUrl() + "] - " + + (!isImpl ? "not " : "") + "directly implemented"); + } + } + if (this.cacheStub) { + this.cachedStub = remoteObj; + } + } + } + + /** + * Create the RMI stub, typically by looking it up. + *

Called on interceptor initialization if "cacheStub" is "true"; + * else called for each invocation by {@link #getStub()}. + *

The default implementation looks up the service URL via + * java.rmi.Naming. This can be overridden in subclasses. + * @return the RMI stub to store in this interceptor + * @throws RemoteLookupFailureException if RMI stub creation failed + * @see #setCacheStub + * @see java.rmi.Naming#lookup + */ + protected Remote lookupStub() throws RemoteLookupFailureException { + try { + Remote stub = null; + if (this.registryClientSocketFactory != null) { + // RMIClientSocketFactory specified for registry access. + // Unfortunately, due to RMI API limitations, this means + // that we need to parse the RMI URL ourselves and perform + // straight LocateRegistry.getRegistry/Registry.lookup calls. + URL url = new URL(null, getServiceUrl(), new DummyURLStreamHandler()); + String protocol = url.getProtocol(); + if (protocol != null && !"rmi".equals(protocol)) { + throw new MalformedURLException("Invalid URL scheme '" + protocol + "'"); + } + String host = url.getHost(); + int port = url.getPort(); + String name = url.getPath(); + if (name != null && name.startsWith("/")) { + name = name.substring(1); + } + Registry registry = LocateRegistry.getRegistry(host, port, this.registryClientSocketFactory); + stub = registry.lookup(name); + } + else { + // Can proceed with standard RMI lookup API... + stub = Naming.lookup(getServiceUrl()); + } + if (logger.isDebugEnabled()) { + logger.debug("Located RMI stub with URL [" + getServiceUrl() + "]"); + } + return stub; + } + catch (MalformedURLException ex) { + throw new RemoteLookupFailureException("Service URL [" + getServiceUrl() + "] is invalid", ex); + } + catch (NotBoundException ex) { + throw new RemoteLookupFailureException( + "Could not find RMI service [" + getServiceUrl() + "] in RMI registry", ex); + } + catch (RemoteException ex) { + throw new RemoteLookupFailureException("Lookup of RMI stub failed", ex); + } + } + + /** + * Return the RMI stub to use. Called for each invocation. + *

The default implementation returns the stub created on initialization, + * if any. Else, it invokes {@link #lookupStub} to get a new stub for + * each invocation. This can be overridden in subclasses, for example in + * order to cache a stub for a given amount of time before recreating it, + * or to test the stub whether it is still alive. + * @return the RMI stub to use for an invocation + * @throws RemoteLookupFailureException if RMI stub creation failed + * @see #lookupStub + */ + protected Remote getStub() throws RemoteLookupFailureException { + if (!this.cacheStub || (this.lookupStubOnStartup && !this.refreshStubOnConnectFailure)) { + return (this.cachedStub != null ? this.cachedStub : lookupStub()); + } + else { + synchronized (this.stubMonitor) { + if (this.cachedStub == null) { + this.cachedStub = lookupStub(); + } + return this.cachedStub; + } + } + } + + + /** + * Fetches an RMI stub and delegates to doInvoke. + * If configured to refresh on connect failure, it will call + * {@link #refreshAndRetry} on corresponding RMI exceptions. + * @see #getStub + * @see #doInvoke(MethodInvocation, Remote) + * @see #refreshAndRetry + * @see java.rmi.ConnectException + * @see java.rmi.ConnectIOException + * @see java.rmi.NoSuchObjectException + */ + public Object invoke(MethodInvocation invocation) throws Throwable { + Remote stub = getStub(); + try { + return doInvoke(invocation, stub); + } + catch (RemoteConnectFailureException ex) { + return handleRemoteConnectFailure(invocation, ex); + } + catch (RemoteException ex) { + if (isConnectFailure(ex)) { + return handleRemoteConnectFailure(invocation, ex); + } + else { + throw ex; + } + } + } + + /** + * Determine whether the given RMI exception indicates a connect failure. + *

The default implementation delegates to + * {@link RmiClientInterceptorUtils#isConnectFailure}. + * @param ex the RMI exception to check + * @return whether the exception should be treated as connect failure + */ + protected boolean isConnectFailure(RemoteException ex) { + return RmiClientInterceptorUtils.isConnectFailure(ex); + } + + /** + * Refresh the stub and retry the remote invocation if necessary. + *

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 #setRefreshStubOnConnectFailure + * @see #doInvoke + */ + private Object handleRemoteConnectFailure(MethodInvocation invocation, Exception ex) throws Throwable { + if (this.refreshStubOnConnectFailure) { + String msg = "Could not connect to RMI service [" + getServiceUrl() + "] - retrying"; + if (logger.isDebugEnabled()) { + logger.warn(msg, ex); + } + else if (logger.isWarnEnabled()) { + logger.warn(msg); + } + return refreshAndRetry(invocation); + } + else { + throw ex; + } + } + + /** + * Refresh the RMI stub and retry the given invocation. + * Called by invoke on connect failure. + * @param invocation the AOP method invocation + * @return the invocation result, if any + * @throws Throwable in case of invocation failure + * @see #invoke + */ + protected Object refreshAndRetry(MethodInvocation invocation) throws Throwable { + Remote freshStub = null; + synchronized (this.stubMonitor) { + this.cachedStub = null; + freshStub = lookupStub(); + if (this.cacheStub) { + this.cachedStub = freshStub; + } + } + return doInvoke(invocation, freshStub); + } + + /** + * Perform the given invocation on the given RMI stub. + * @param invocation the AOP method invocation + * @param stub the RMI stub to invoke + * @return the invocation result, if any + * @throws Throwable in case of invocation failure + */ + protected Object doInvoke(MethodInvocation invocation, Remote stub) throws Throwable { + if (stub instanceof RmiInvocationHandler) { + // RMI invoker + try { + return doInvoke(invocation, (RmiInvocationHandler) stub); + } + catch (RemoteException ex) { + throw RmiClientInterceptorUtils.convertRmiAccessException( + invocation.getMethod(), ex, isConnectFailure(ex), getServiceUrl()); + } + catch (InvocationTargetException ex) { + Throwable exToThrow = ex.getTargetException(); + RemoteInvocationUtils.fillInClientStackTraceIfPossible(exToThrow); + throw exToThrow; + } + catch (Throwable ex) { + throw new RemoteInvocationFailureException("Invocation of method [" + invocation.getMethod() + + "] failed in RMI service [" + getServiceUrl() + "]", ex); + } + } + else { + // traditional RMI stub + try { + return RmiClientInterceptorUtils.invokeRemoteMethod(invocation, stub); + } + catch (InvocationTargetException ex) { + Throwable targetEx = ex.getTargetException(); + if (targetEx instanceof RemoteException) { + RemoteException rex = (RemoteException) targetEx; + throw RmiClientInterceptorUtils.convertRmiAccessException( + invocation.getMethod(), rex, isConnectFailure(rex), getServiceUrl()); + } + else { + throw targetEx; + } + } + } + } + + /** + * Apply the given AOP method invocation to the given {@link RmiInvocationHandler}. + *

The default implementation delegates to {@link #createRemoteInvocation}. + * @param methodInvocation the current AOP method invocation + * @param invocationHandler the RmiInvocationHandler to apply the invocation to + * @return the invocation result + * @throws RemoteException in case of communication errors + * @throws NoSuchMethodException if the method name could not be resolved + * @throws IllegalAccessException if the method could not be accessed + * @throws InvocationTargetException if the method invocation resulted in an exception + * @see org.springframework.remoting.support.RemoteInvocation + */ + protected Object doInvoke(MethodInvocation methodInvocation, RmiInvocationHandler invocationHandler) + throws RemoteException, NoSuchMethodException, IllegalAccessException, InvocationTargetException { + + if (AopUtils.isToStringMethod(methodInvocation.getMethod())) { + return "RMI invoker proxy for service URL [" + getServiceUrl() + "]"; + } + + return invocationHandler.invoke(createRemoteInvocation(methodInvocation)); + } + + + /** + * Dummy URLStreamHandler that's just specified to suppress the standard + * java.net.URL URLStreamHandler lookup, to be able to + * use the standard URL class for parsing "rmi:..." URLs. + */ + private static class DummyURLStreamHandler extends URLStreamHandler { + + protected URLConnection openConnection(URL url) throws IOException { + throw new UnsupportedOperationException(); + } + } + +} Index: 3rdParty_sources/spring/org/springframework/remoting/rmi/RmiClientInterceptorUtils.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/remoting/rmi/RmiClientInterceptorUtils.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/remoting/rmi/RmiClientInterceptorUtils.java 17 Aug 2012 15:16:15 -0000 1.1 @@ -0,0 +1,230 @@ +/* + * 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.remoting.rmi; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.rmi.ConnectException; +import java.rmi.ConnectIOException; +import java.rmi.NoSuchObjectException; +import java.rmi.Remote; +import java.rmi.RemoteException; +import java.rmi.StubNotFoundException; +import java.rmi.UnknownHostException; + +import org.aopalliance.intercept.MethodInvocation; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.omg.CORBA.COMM_FAILURE; +import org.omg.CORBA.CompletionStatus; +import org.omg.CORBA.NO_RESPONSE; +import org.omg.CORBA.SystemException; + +import org.springframework.remoting.RemoteAccessException; +import org.springframework.remoting.RemoteConnectFailureException; +import org.springframework.remoting.RemoteProxyFailureException; +import org.springframework.util.ReflectionUtils; + +/** + * Factored-out methods for performing invocations within an RMI client. + * Can handle both RMI and non-RMI service interfaces working on an RMI stub. + * + *

Note: This is an SPI class, not intended to be used by applications. + * + * @author Juergen Hoeller + * @since 1.1 + */ +public abstract class RmiClientInterceptorUtils { + + private static final String ORACLE_CONNECTION_EXCEPTION = "com.evermind.server.rmi.RMIConnectionException"; + + private static final Log logger = LogFactory.getLog(RmiClientInterceptorUtils.class); + + + /** + * Apply the given method invocation to the given RMI stub. + *

Delegates to the corresponding method if the RMI stub does not directly + * implement the invoked method. This typically happens when a non-RMI service + * interface is used for an RMI service. The methods of such a service interface + * have to match the RMI stub methods, but they typically don't declare + * java.rmi.RemoteException: A RemoteException thrown by the RMI stub + * will be automatically converted to Spring's RemoteAccessException. + * @deprecated as of Spring 2.5, in favor of {@link #invokeRemoteMethod} + */ + public static Object invoke(MethodInvocation invocation, Remote stub, String serviceName) throws Throwable { + try { + return invokeRemoteMethod(invocation, stub); + } + catch (InvocationTargetException ex) { + Throwable targetEx = ex.getTargetException(); + if (targetEx instanceof RemoteException) { + RemoteException rex = (RemoteException) targetEx; + throw convertRmiAccessException(invocation.getMethod(), rex, serviceName); + } + else { + throw targetEx; + } + } + } + + /** + * Perform a raw method invocation on the given RMI stub, + * letting reflection exceptions through as-is. + * @deprecated as of Spring 2.5, in favor of {@link #invokeRemoteMethod} + */ + public static Object doInvoke(MethodInvocation invocation, Remote stub) throws InvocationTargetException { + return invokeRemoteMethod(invocation, stub); + } + + /** + * Perform a raw method invocation on the given RMI stub, + * letting reflection exceptions through as-is. + * @param invocation the AOP MethodInvocation + * @param stub the RMI stub + * @return the invocation result, if any + * @throws InvocationTargetException if thrown by reflection + */ + public static Object invokeRemoteMethod(MethodInvocation invocation, Object stub) + throws InvocationTargetException { + + Method method = invocation.getMethod(); + try { + if (method.getDeclaringClass().isInstance(stub)) { + // directly implemented + return method.invoke(stub, invocation.getArguments()); + } + else { + // not directly implemented + Method stubMethod = stub.getClass().getMethod(method.getName(), method.getParameterTypes()); + return stubMethod.invoke(stub, invocation.getArguments()); + } + } + catch (InvocationTargetException ex) { + throw ex; + } + catch (NoSuchMethodException ex) { + throw new RemoteProxyFailureException("No matching RMI stub method found for: " + method, ex); + } + catch (Throwable ex) { + throw new RemoteProxyFailureException("Invocation of RMI stub method failed: " + method, ex); + } + } + + /** + * Wrap the given arbitrary exception that happened during remote access + * in either a RemoteException or a Spring RemoteAccessException (if the + * method signature does not support RemoteException). + *

Only call this for remote access exceptions, not for exceptions + * thrown by the target service itself! + * @param method the invoked method + * @param ex the exception that happened, to be used as cause for the + * RemoteAccessException or RemoteException + * @param message the message for the RemoteAccessException respectively + * RemoteException + * @return the exception to be thrown to the caller + */ + public static Exception convertRmiAccessException(Method method, Throwable ex, String message) { + if (logger.isDebugEnabled()) { + logger.debug(message, ex); + } + if (ReflectionUtils.declaresException(method, RemoteException.class)) { + return new RemoteException(message, ex); + } + else { + return new RemoteAccessException(message, ex); + } + } + + /** + * Convert the given RemoteException that happened during remote access + * to Spring's RemoteAccessException if the method signature does not + * support RemoteException. Else, return the original RemoteException. + * @param method the invoked method + * @param ex the RemoteException that happened + * @param serviceName the name of the service (for debugging purposes) + * @return the exception to be thrown to the caller + */ + public static Exception convertRmiAccessException(Method method, RemoteException ex, String serviceName) { + return convertRmiAccessException(method, ex, isConnectFailure(ex), serviceName); + } + + /** + * Convert the given RemoteException that happened during remote access + * to Spring's RemoteAccessException if the method signature does not + * support RemoteException. Else, return the original RemoteException. + * @param method the invoked method + * @param ex the RemoteException that happened + * @param isConnectFailure whether the given exception should be considered + * a connect failure + * @param serviceName the name of the service (for debugging purposes) + * @return the exception to be thrown to the caller + */ + public static Exception convertRmiAccessException( + Method method, RemoteException ex, boolean isConnectFailure, String serviceName) { + + if (logger.isDebugEnabled()) { + logger.debug("Remote service [" + serviceName + "] threw exception", ex); + } + if (ReflectionUtils.declaresException(method, ex.getClass())) { + return ex; + } + else { + if (isConnectFailure) { + return new RemoteConnectFailureException("Could not connect to remote service [" + serviceName + "]", ex); + } + else { + return new RemoteAccessException("Could not access remote service [" + serviceName + "]", ex); + } + } + } + + /** + * Determine whether the given RMI exception indicates a connect failure. + *

Treats RMI's ConnectException, ConnectIOException, UnknownHostException, + * NoSuchObjectException and StubNotFoundException as connect failure, + * as well as Oracle's OC4J com.evermind.server.rmi.RMIConnectionException + * (which doesn't derive from from any well-known RMI connect exception). + * @param ex the RMI exception to check + * @return whether the exception should be treated as connect failure + * @see java.rmi.ConnectException + * @see java.rmi.ConnectIOException + * @see java.rmi.UnknownHostException + * @see java.rmi.NoSuchObjectException + * @see java.rmi.StubNotFoundException + */ + public static boolean isConnectFailure(RemoteException ex) { + return (ex instanceof ConnectException || ex instanceof ConnectIOException || + ex instanceof UnknownHostException || ex instanceof NoSuchObjectException || + ex instanceof StubNotFoundException || isCorbaConnectFailure(ex.getCause()) || + ORACLE_CONNECTION_EXCEPTION.equals(ex.getClass().getName())); + } + + /** + * Check whether the given RMI exception root cause indicates a CORBA + * connection failure. + *

This is relevant on the IBM JVM, in particular for WebSphere EJB clients. + *

See the + * IBM website + * for details. + * @param ex the RMI exception to check + */ + private static boolean isCorbaConnectFailure(Throwable ex) { + return ((ex instanceof COMM_FAILURE || ex instanceof NO_RESPONSE) && + ((SystemException) ex).completed == CompletionStatus.COMPLETED_NO); + } + +} Index: 3rdParty_sources/spring/org/springframework/remoting/rmi/RmiInvocationHandler.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/remoting/rmi/RmiInvocationHandler.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/remoting/rmi/RmiInvocationHandler.java 17 Aug 2012 15:16:15 -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.remoting.rmi; + +import java.lang.reflect.InvocationTargetException; +import java.rmi.Remote; +import java.rmi.RemoteException; + +import org.springframework.remoting.support.RemoteInvocation; + +/** + * Interface for RMI invocation handlers instances on the server, + * wrapping exported services. A client uses a stub implementing + * this interface to access such a service. + * + *

This is an SPI interface, not to be used directly by applications. + * + * @author Juergen Hoeller + * @since 14.05.2003 + */ +public interface RmiInvocationHandler extends Remote { + + /** + * Return the name of the target interface that this invoker operates on. + * @return the name of the target interface, or null if none + * @throws RemoteException in case of communication errors + * @see RmiServiceExporter#getServiceInterface() + */ + public String getTargetInterfaceName() throws RemoteException; + + /** + * Apply the given invocation to the target object. + *

Called by + * {@link RmiClientInterceptor#doInvoke(org.aopalliance.intercept.MethodInvocation, RmiInvocationHandler)}. + * @param invocation object that encapsulates invocation parameters + * @return the object returned from the invoked method, if any + * @throws RemoteException in case of communication errors + * @throws NoSuchMethodException if the method name could not be resolved + * @throws IllegalAccessException if the method could not be accessed + * @throws InvocationTargetException if the method invocation resulted in an exception + */ + public Object invoke(RemoteInvocation invocation) + throws RemoteException, NoSuchMethodException, IllegalAccessException, InvocationTargetException; + +} Index: 3rdParty_sources/spring/org/springframework/remoting/rmi/RmiInvocationWrapper.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/remoting/rmi/RmiInvocationWrapper.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/remoting/rmi/RmiInvocationWrapper.java 17 Aug 2012 15:16:15 -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.remoting.rmi; + +import java.lang.reflect.InvocationTargetException; +import java.rmi.RemoteException; + +import org.springframework.remoting.support.RemoteInvocation; +import org.springframework.util.Assert; + +/** + * Server-side implementation of {@link RmiInvocationHandler}. An instance + * of this class exists for each remote object. Automatically created + * by {@link RmiServiceExporter} for non-RMI service implementations. + * + *

This is an SPI class, not to be used directly by applications. + * + * @author Juergen Hoeller + * @since 14.05.2003 + * @see RmiServiceExporter + */ +class RmiInvocationWrapper implements RmiInvocationHandler { + + private final Object wrappedObject; + + private final RmiBasedExporter rmiExporter; + + + /** + * Create a new RmiInvocationWrapper for the given object + * @param wrappedObject the object to wrap with an RmiInvocationHandler + * @param rmiExporter the RMI exporter to handle the actual invocation + */ + public RmiInvocationWrapper(Object wrappedObject, RmiBasedExporter rmiExporter) { + Assert.notNull(wrappedObject, "Object to wrap is required"); + Assert.notNull(rmiExporter, "RMI exporter is required"); + this.wrappedObject = wrappedObject; + this.rmiExporter = rmiExporter; + } + + + /** + * Exposes the exporter's service interface, if any, as target interface. + * @see RmiBasedExporter#getServiceInterface() + */ + public String getTargetInterfaceName() { + Class ifc = this.rmiExporter.getServiceInterface(); + return (ifc != null ? ifc.getName() : null); + } + + /** + * Delegates the actual invocation handling to the RMI exporter. + * @see RmiBasedExporter#invoke(org.springframework.remoting.support.RemoteInvocation, Object) + */ + public Object invoke(RemoteInvocation invocation) + throws RemoteException, NoSuchMethodException, IllegalAccessException, InvocationTargetException { + + return this.rmiExporter.invoke(invocation, this.wrappedObject); + } + +} Index: 3rdParty_sources/spring/org/springframework/remoting/rmi/RmiInvocationWrapperRTD.xml =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/remoting/rmi/RmiInvocationWrapperRTD.xml,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/remoting/rmi/RmiInvocationWrapperRTD.xml 17 Aug 2012 15:16:15 -0000 1.1 @@ -0,0 +1,11 @@ + + + + + + + + Index: 3rdParty_sources/spring/org/springframework/remoting/rmi/RmiProxyFactoryBean.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/remoting/rmi/RmiProxyFactoryBean.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/remoting/rmi/RmiProxyFactoryBean.java 17 Aug 2012 15:16:15 -0000 1.1 @@ -0,0 +1,87 @@ +/* + * 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.remoting.rmi; + +import org.springframework.aop.framework.ProxyFactory; +import org.springframework.beans.factory.BeanClassLoaderAware; +import org.springframework.beans.factory.FactoryBean; + +/** + * FactoryBean for RMI proxies, supporting both conventional RMI services and + * RMI invokers. Exposes the proxied service for use as a bean reference, + * using the specified service interface. Proxies will throw Spring's unchecked + * RemoteAccessException on remote invocation failure instead of RMI's RemoteException. + * + *

The service URL must be a valid RMI URL like "rmi://localhost:1099/myservice". + * RMI invokers work at the RmiInvocationHandler level, using the same invoker stub + * for any service. Service interfaces do not have to extend java.rmi.Remote + * or throw java.rmi.RemoteException. Of course, in and out parameters + * have to be serializable. + * + *

With conventional RMI services, this proxy factory is typically used with the + * RMI service interface. Alternatively, this factory can also proxy a remote RMI + * service with a matching non-RMI business interface, i.e. an interface that mirrors + * the RMI service methods but does not declare RemoteExceptions. In the latter case, + * RemoteExceptions thrown by the RMI stub will automatically get converted to + * Spring's unchecked RemoteAccessException. + * + *

The major advantage of RMI, compared to Hessian and Burlap, is serialization. + * Effectively, any serializable Java object can be transported without hassle. + * Hessian and Burlap have their own (de-)serialization mechanisms, but are + * HTTP-based and thus much easier to setup than RMI. Alternatively, consider + * Spring's HTTP invoker to combine Java serialization with HTTP-based transport. + * + * @author Juergen Hoeller + * @since 13.05.2003 + * @see #setServiceInterface + * @see #setServiceUrl + * @see RmiClientInterceptor + * @see RmiServiceExporter + * @see java.rmi.Remote + * @see java.rmi.RemoteException + * @see org.springframework.remoting.RemoteAccessException + * @see org.springframework.remoting.caucho.HessianProxyFactoryBean + * @see org.springframework.remoting.caucho.BurlapProxyFactoryBean + * @see org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean + */ +public class RmiProxyFactoryBean extends RmiClientInterceptor implements FactoryBean, BeanClassLoaderAware { + + private Object serviceProxy; + + + public void afterPropertiesSet() { + super.afterPropertiesSet(); + if (getServiceInterface() == null) { + throw new IllegalArgumentException("Property 'serviceInterface' is required"); + } + this.serviceProxy = new ProxyFactory(getServiceInterface(), this).getProxy(getBeanClassLoader()); + } + + + public Object getObject() { + return this.serviceProxy; + } + + public Class getObjectType() { + return getServiceInterface(); + } + + public boolean isSingleton() { + return true; + } + +} Index: 3rdParty_sources/spring/org/springframework/remoting/rmi/RmiRegistryFactoryBean.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/remoting/rmi/RmiRegistryFactoryBean.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/remoting/rmi/RmiRegistryFactoryBean.java 17 Aug 2012 15:16:15 -0000 1.1 @@ -0,0 +1,305 @@ +/* + * 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.remoting.rmi; + +import java.rmi.RemoteException; +import java.rmi.registry.LocateRegistry; +import java.rmi.registry.Registry; +import java.rmi.server.RMIClientSocketFactory; +import java.rmi.server.RMIServerSocketFactory; +import java.rmi.server.UnicastRemoteObject; + +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; + +/** + * FactoryBean that locates a {@link java.rmi.registry.Registry} and + * exposes it for bean references. Can also create a local RMI registry + * on the fly if none exists already. + * + *

Can be used to set up and pass around the actual Registry object to + * applications objects that need to work with RMI. One example for such an + * object that needs to work with RMI is Spring's {@link RmiServiceExporter}, + * which either works with a passed-in Registry reference or falls back to + * the registry as specified by its local properties and defaults. + * + *

Also useful to enforce creation of a local RMI registry at a given port, + * for example for a JMX connector. If used in conjunction with + * {@link org.springframework.jmx.support.ConnectorServerFactoryBean}, + * it is recommended to mark the connector definition (ConnectorServerFactoryBean) + * as "depends-on" the registry definition (RmiRegistryFactoryBean), + * to guarantee starting up the registry first. + * + *

Note: The implementation of this class mirrors the corresponding logic + * in {@link RmiServiceExporter}, and also offers the same customization hooks. + * RmiServiceExporter implements its own registry lookup as a convenience: + * It is very common to simply rely on the registry defaults. + * + * @author Juergen Hoeller + * @since 1.2.3 + * @see RmiServiceExporter#setRegistry + * @see org.springframework.jmx.support.ConnectorServerFactoryBean + * @see java.rmi.registry.Registry + * @see java.rmi.registry.LocateRegistry + */ +public class RmiRegistryFactoryBean implements FactoryBean, InitializingBean, DisposableBean { + + protected final Log logger = LogFactory.getLog(getClass()); + + private String host; + + private int port = Registry.REGISTRY_PORT; + + private RMIClientSocketFactory clientSocketFactory; + + private RMIServerSocketFactory serverSocketFactory; + + private Registry registry; + + private boolean alwaysCreate = false; + + private boolean created = false; + + + /** + * Set the host of the registry for the exported RMI service, + * i.e. rmi://HOST:port/name + *

Default is localhost. + */ + public void setHost(String host) { + this.host = host; + } + + /** + * Return the host of the registry for the exported RMI service. + */ + public String getHost() { + return this.host; + } + + /** + * Set the port of the registry for the exported RMI service, + * i.e. rmi://host:PORT/name + *

Default is Registry.REGISTRY_PORT (1099). + */ + public void setPort(int port) { + this.port = port; + } + + /** + * Return the port of the registry for the exported RMI service. + */ + public int getPort() { + return this.port; + } + + /** + * Set a custom RMI client socket factory to use for the RMI registry. + *

If the given object also implements java.rmi.server.RMIServerSocketFactory, + * it will automatically be registered as server socket factory too. + * @see #setServerSocketFactory + * @see java.rmi.server.RMIClientSocketFactory + * @see java.rmi.server.RMIServerSocketFactory + * @see java.rmi.registry.LocateRegistry#getRegistry(String, int, java.rmi.server.RMIClientSocketFactory) + */ + public void setClientSocketFactory(RMIClientSocketFactory clientSocketFactory) { + this.clientSocketFactory = clientSocketFactory; + } + + /** + * Set a custom RMI server socket factory to use for the RMI registry. + *

Only needs to be specified when the client socket factory does not + * implement java.rmi.server.RMIServerSocketFactory already. + * @see #setClientSocketFactory + * @see java.rmi.server.RMIClientSocketFactory + * @see java.rmi.server.RMIServerSocketFactory + * @see java.rmi.registry.LocateRegistry#createRegistry(int, RMIClientSocketFactory, java.rmi.server.RMIServerSocketFactory) + */ + public void setServerSocketFactory(RMIServerSocketFactory serverSocketFactory) { + this.serverSocketFactory = serverSocketFactory; + } + + /** + * Set whether to always create the registry in-process, + * not attempting to locate an existing registry at the specified port. + *

Default is "false". Switch this flag to "true" in order to avoid + * the overhead of locating an existing registry when you always + * intend to create a new registry in any case. + */ + public void setAlwaysCreate(boolean alwaysCreate) { + this.alwaysCreate = alwaysCreate; + } + + + public void afterPropertiesSet() throws Exception { + // Check socket factories for registry. + if (this.clientSocketFactory instanceof RMIServerSocketFactory) { + this.serverSocketFactory = (RMIServerSocketFactory) this.clientSocketFactory; + } + if ((this.clientSocketFactory != null && this.serverSocketFactory == null) || + (this.clientSocketFactory == null && this.serverSocketFactory != null)) { + throw new IllegalArgumentException( + "Both RMIClientSocketFactory and RMIServerSocketFactory or none required"); + } + + // Fetch RMI registry to expose. + this.registry = getRegistry(this.host, this.port, this.clientSocketFactory, this.serverSocketFactory); + } + + + /** + * Locate or create the RMI registry. + * @param registryHost the registry host to use (if this is specified, + * no implicit creation of a RMI registry will happen) + * @param registryPort the registry port to use + * @param clientSocketFactory the RMI client socket factory for the registry (if any) + * @param serverSocketFactory the RMI server socket factory for the registry (if any) + * @return the RMI registry + * @throws java.rmi.RemoteException if the registry couldn't be located or created + */ + protected Registry getRegistry(String registryHost, int registryPort, + RMIClientSocketFactory clientSocketFactory, RMIServerSocketFactory serverSocketFactory) + throws RemoteException { + + if (registryHost != null) { + // Host explictly specified: only lookup possible. + if (logger.isInfoEnabled()) { + logger.info("Looking for RMI registry at port '" + registryPort + "' of host [" + registryHost + "]"); + } + Registry reg = LocateRegistry.getRegistry(registryHost, registryPort, clientSocketFactory); + testRegistry(reg); + return reg; + } + + else { + return getRegistry(registryPort, clientSocketFactory, serverSocketFactory); + } + } + + /** + * Locate or create the RMI registry. + * @param registryPort the registry port to use + * @param clientSocketFactory the RMI client socket factory for the registry (if any) + * @param serverSocketFactory the RMI server socket factory for the registry (if any) + * @return the RMI registry + * @throws RemoteException if the registry couldn't be located or created + */ + protected Registry getRegistry( + int registryPort, RMIClientSocketFactory clientSocketFactory, RMIServerSocketFactory serverSocketFactory) + throws RemoteException { + + if (clientSocketFactory != null) { + if (this.alwaysCreate) { + logger.info("Creating new RMI registry"); + this.created = true; + return LocateRegistry.createRegistry(registryPort, clientSocketFactory, serverSocketFactory); + } + if (logger.isInfoEnabled()) { + logger.info("Looking for RMI registry at port '" + registryPort + "', using custom socket factory"); + } + try { + // Retrieve existing registry. + Registry reg = LocateRegistry.getRegistry(null, registryPort, clientSocketFactory); + testRegistry(reg); + return reg; + } + catch (RemoteException ex) { + logger.debug("RMI registry access threw exception", ex); + logger.info("Could not detect RMI registry - creating new one"); + // Assume no registry found -> create new one. + this.created = true; + return LocateRegistry.createRegistry(registryPort, clientSocketFactory, serverSocketFactory); + } + } + + else { + return getRegistry(registryPort); + } + } + + /** + * Locate or create the RMI registry. + * @param registryPort the registry port to use + * @return the RMI registry + * @throws RemoteException if the registry couldn't be located or created + */ + protected Registry getRegistry(int registryPort) throws RemoteException { + if (this.alwaysCreate) { + logger.info("Creating new RMI registry"); + this.created = true; + return LocateRegistry.createRegistry(registryPort); + } + if (logger.isInfoEnabled()) { + logger.info("Looking for RMI registry at port '" + registryPort + "'"); + } + try { + // Retrieve existing registry. + Registry reg = LocateRegistry.getRegistry(registryPort); + testRegistry(reg); + return reg; + } + catch (RemoteException ex) { + logger.debug("RMI registry access threw exception", ex); + logger.info("Could not detect RMI registry - creating new one"); + // Assume no registry found -> create new one. + this.created = true; + return LocateRegistry.createRegistry(registryPort); + } + } + + /** + * Test the given RMI registry, calling some operation on it to + * check whether it is still active. + *

Default implementation calls Registry.list(). + * @param registry the RMI registry to test + * @throws RemoteException if thrown by registry methods + * @see java.rmi.registry.Registry#list() + */ + protected void testRegistry(Registry registry) throws RemoteException { + registry.list(); + } + + + public Object getObject() throws Exception { + return this.registry; + } + + public Class getObjectType() { + return (this.registry != null ? this.registry.getClass() : Registry.class); + } + + public boolean isSingleton() { + return true; + } + + + /** + * Unexport the RMI registry on bean factory shutdown, + * provided that this bean actually created a registry. + */ + public void destroy() throws RemoteException { + if (this.created) { + logger.info("Unexporting RMI registry"); + UnicastRemoteObject.unexportObject(this.registry, true); + } + } + +} Index: 3rdParty_sources/spring/org/springframework/remoting/rmi/RmiServiceExporter.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/remoting/rmi/RmiServiceExporter.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/remoting/rmi/RmiServiceExporter.java 17 Aug 2012 15:16:15 -0000 1.1 @@ -0,0 +1,451 @@ +/* + * 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.remoting.rmi; + +import java.rmi.AlreadyBoundException; +import java.rmi.NoSuchObjectException; +import java.rmi.NotBoundException; +import java.rmi.Remote; +import java.rmi.RemoteException; +import java.rmi.registry.LocateRegistry; +import java.rmi.registry.Registry; +import java.rmi.server.RMIClientSocketFactory; +import java.rmi.server.RMIServerSocketFactory; +import java.rmi.server.UnicastRemoteObject; + +import org.springframework.beans.factory.DisposableBean; +import org.springframework.beans.factory.InitializingBean; + +/** + * RMI exporter that exposes the specified service as RMI object with the specified name. + * Such services can be accessed via plain RMI or via {@link RmiProxyFactoryBean}. + * Also supports exposing any non-RMI service via RMI invokers, to be accessed via + * {@link RmiClientInterceptor} / {@link RmiProxyFactoryBean}'s automatic detection + * of such invokers. + * + *

With an RMI invoker, RMI communication works on the {@link RmiInvocationHandler} + * level, needing only one stub for any service. Service interfaces do not have to + * extend java.rmi.Remote or throw java.rmi.RemoteException + * on all methods, but in and out parameters have to be serializable. + * + *

The major advantage of RMI, compared to Hessian and Burlap, is serialization. + * Effectively, any serializable Java object can be transported without hassle. + * Hessian and Burlap have their own (de-)serialization mechanisms, but are + * HTTP-based and thus much easier to setup than RMI. Alternatively, consider + * Spring's HTTP invoker to combine Java serialization with HTTP-based transport. + * + *

Note: RMI makes a best-effort attempt to obtain the fully qualified host name. + * If one cannot be determined, it will fall back and use the IP address. Depending + * on your network configuration, in some cases it will resolve the IP to the loopback + * address. To ensure that RMI will use the host name bound to the correct network + * interface, you should pass the java.rmi.server.hostname property to the + * JVM that will export the registry and/or the service using the "-D" JVM argument. + * For example: -Djava.rmi.server.hostname=myserver.com + * + * @author Juergen Hoeller + * @since 13.05.2003 + * @see RmiClientInterceptor + * @see RmiProxyFactoryBean + * @see java.rmi.Remote + * @see java.rmi.RemoteException + * @see org.springframework.remoting.caucho.HessianServiceExporter + * @see org.springframework.remoting.caucho.BurlapServiceExporter + * @see org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter + */ +public class RmiServiceExporter extends RmiBasedExporter implements InitializingBean, DisposableBean { + + private String serviceName; + + private int servicePort = 0; // anonymous port + + private RMIClientSocketFactory clientSocketFactory; + + private RMIServerSocketFactory serverSocketFactory; + + private Registry registry; + + private String registryHost; + + private int registryPort = Registry.REGISTRY_PORT; + + private RMIClientSocketFactory registryClientSocketFactory; + + private RMIServerSocketFactory registryServerSocketFactory; + + private boolean alwaysCreateRegistry = false; + + private boolean replaceExistingBinding = true; + + private Remote exportedObject; + + + /** + * Set the name of the exported RMI service, + * i.e. rmi://host:port/NAME + */ + public void setServiceName(String serviceName) { + this.serviceName = serviceName; + } + + /** + * Set the port that the exported RMI service will use. + *

Default is 0 (anonymous port). + */ + public void setServicePort(int servicePort) { + this.servicePort = servicePort; + } + + /** + * Set a custom RMI client socket factory to use for exporting the service. + *

If the given object also implements java.rmi.server.RMIServerSocketFactory, + * it will automatically be registered as server socket factory too. + * @see #setServerSocketFactory + * @see java.rmi.server.RMIClientSocketFactory + * @see java.rmi.server.RMIServerSocketFactory + * @see UnicastRemoteObject#exportObject(Remote, int, RMIClientSocketFactory, RMIServerSocketFactory) + */ + public void setClientSocketFactory(RMIClientSocketFactory clientSocketFactory) { + this.clientSocketFactory = clientSocketFactory; + } + + /** + * Set a custom RMI server socket factory to use for exporting the service. + *

Only needs to be specified when the client socket factory does not + * implement java.rmi.server.RMIServerSocketFactory already. + * @see #setClientSocketFactory + * @see java.rmi.server.RMIClientSocketFactory + * @see java.rmi.server.RMIServerSocketFactory + * @see UnicastRemoteObject#exportObject(Remote, int, RMIClientSocketFactory, RMIServerSocketFactory) + */ + public void setServerSocketFactory(RMIServerSocketFactory serverSocketFactory) { + this.serverSocketFactory = serverSocketFactory; + } + + /** + * Specify the RMI registry to register the exported service with. + * Typically used in combination with RmiRegistryFactoryBean. + *

Alternatively, you can specify all registry properties locally. + * This exporter will then try to locate the specified registry, + * automatically creating a new local one if appropriate. + *

Default is a local registry at the default port (1099), + * created on the fly if necessary. + * @see RmiRegistryFactoryBean + * @see #setRegistryHost + * @see #setRegistryPort + * @see #setRegistryClientSocketFactory + * @see #setRegistryServerSocketFactory + */ + public void setRegistry(Registry registry) { + this.registry = registry; + } + + /** + * Set the host of the registry for the exported RMI service, + * i.e. rmi://HOST:port/name + *

Default is localhost. + */ + public void setRegistryHost(String registryHost) { + this.registryHost = registryHost; + } + + /** + * Set the port of the registry for the exported RMI service, + * i.e. rmi://host:PORT/name + *

Default is Registry.REGISTRY_PORT (1099). + * @see java.rmi.registry.Registry#REGISTRY_PORT + */ + public void setRegistryPort(int registryPort) { + this.registryPort = registryPort; + } + + /** + * Set a custom RMI client socket factory to use for the RMI registry. + *

If the given object also implements java.rmi.server.RMIServerSocketFactory, + * it will automatically be registered as server socket factory too. + * @see #setRegistryServerSocketFactory + * @see java.rmi.server.RMIClientSocketFactory + * @see java.rmi.server.RMIServerSocketFactory + * @see LocateRegistry#getRegistry(String, int, RMIClientSocketFactory) + */ + public void setRegistryClientSocketFactory(RMIClientSocketFactory registryClientSocketFactory) { + this.registryClientSocketFactory = registryClientSocketFactory; + } + + /** + * Set a custom RMI server socket factory to use for the RMI registry. + *

Only needs to be specified when the client socket factory does not + * implement java.rmi.server.RMIServerSocketFactory already. + * @see #setRegistryClientSocketFactory + * @see java.rmi.server.RMIClientSocketFactory + * @see java.rmi.server.RMIServerSocketFactory + * @see LocateRegistry#createRegistry(int, RMIClientSocketFactory, RMIServerSocketFactory) + */ + public void setRegistryServerSocketFactory(RMIServerSocketFactory registryServerSocketFactory) { + this.registryServerSocketFactory = registryServerSocketFactory; + } + + /** + * Set whether to always create the registry in-process, + * not attempting to locate an existing registry at the specified port. + *

Default is "false". Switch this flag to "true" in order to avoid + * the overhead of locating an existing registry when you always + * intend to create a new registry in any case. + */ + public void setAlwaysCreateRegistry(boolean alwaysCreateRegistry) { + this.alwaysCreateRegistry = alwaysCreateRegistry; + } + + /** + * Set whether to replace an existing binding in the RMI registry, + * that is, whether to simply override an existing binding with the + * specified service in case of a naming conflict in the registry. + *

Default is "true", assuming that an existing binding for this + * exporter's service name is an accidental leftover from a previous + * execution. Switch this to "false" to make the exporter fail in such + * a scenario, indicating that there was already an RMI object bound. + */ + public void setReplaceExistingBinding(boolean replaceExistingBinding) { + this.replaceExistingBinding = replaceExistingBinding; + } + + + public void afterPropertiesSet() throws RemoteException { + prepare(); + } + + /** + * Initialize this service exporter, registering the service as RMI object. + *

Creates an RMI registry on the specified port if none exists. + * @throws RemoteException if service registration failed + */ + public void prepare() throws RemoteException { + checkService(); + + if (this.serviceName == null) { + throw new IllegalArgumentException("Property 'serviceName' is required"); + } + + // Check socket factories for exported object. + if (this.clientSocketFactory instanceof RMIServerSocketFactory) { + this.serverSocketFactory = (RMIServerSocketFactory) this.clientSocketFactory; + } + if ((this.clientSocketFactory != null && this.serverSocketFactory == null) || + (this.clientSocketFactory == null && this.serverSocketFactory != null)) { + throw new IllegalArgumentException( + "Both RMIClientSocketFactory and RMIServerSocketFactory or none required"); + } + + // Check socket factories for RMI registry. + if (this.registryClientSocketFactory instanceof RMIServerSocketFactory) { + this.registryServerSocketFactory = (RMIServerSocketFactory) this.registryClientSocketFactory; + } + if (this.registryClientSocketFactory == null && this.registryServerSocketFactory != null) { + throw new IllegalArgumentException( + "RMIServerSocketFactory without RMIClientSocketFactory for registry not supported"); + } + + // Determine RMI registry to use. + if (this.registry == null) { + this.registry = getRegistry(this.registryHost, this.registryPort, + this.registryClientSocketFactory, this.registryServerSocketFactory); + } + + // Initialize and cache exported object. + this.exportedObject = getObjectToExport(); + + if (logger.isInfoEnabled()) { + logger.info("Binding service '" + this.serviceName + "' to RMI registry: " + this.registry); + } + + // Export RMI object. + if (this.clientSocketFactory != null) { + UnicastRemoteObject.exportObject( + this.exportedObject, this.servicePort, this.clientSocketFactory, this.serverSocketFactory); + } + else { + UnicastRemoteObject.exportObject(this.exportedObject, this.servicePort); + } + + // Bind RMI object to registry. + try { + if (this.replaceExistingBinding) { + this.registry.rebind(this.serviceName, this.exportedObject); + } + else { + this.registry.bind(this.serviceName, this.exportedObject); + } + } + catch (AlreadyBoundException ex) { + // Already an RMI object bound for the specified service name... + unexportObjectSilently(); + throw new IllegalStateException( + "Already an RMI object bound for name '" + this.serviceName + "': " + ex.toString()); + } + catch (RemoteException ex) { + // Registry binding failed: let's unexport the RMI object as well. + unexportObjectSilently(); + throw ex; + } + } + + + /** + * Locate or create the RMI registry for this exporter. + * @param registryHost the registry host to use (if this is specified, + * no implicit creation of a RMI registry will happen) + * @param registryPort the registry port to use + * @param clientSocketFactory the RMI client socket factory for the registry (if any) + * @param serverSocketFactory the RMI server socket factory for the registry (if any) + * @return the RMI registry + * @throws RemoteException if the registry couldn't be located or created + */ + protected Registry getRegistry(String registryHost, int registryPort, + RMIClientSocketFactory clientSocketFactory, RMIServerSocketFactory serverSocketFactory) + throws RemoteException { + + if (registryHost != null) { + // Host explictly specified: only lookup possible. + if (logger.isInfoEnabled()) { + logger.info("Looking for RMI registry at port '" + registryPort + "' of host [" + registryHost + "]"); + } + Registry reg = LocateRegistry.getRegistry(registryHost, registryPort, clientSocketFactory); + testRegistry(reg); + return reg; + } + + else { + return getRegistry(registryPort, clientSocketFactory, serverSocketFactory); + } + } + + /** + * Locate or create the RMI registry for this exporter. + * @param registryPort the registry port to use + * @param clientSocketFactory the RMI client socket factory for the registry (if any) + * @param serverSocketFactory the RMI server socket factory for the registry (if any) + * @return the RMI registry + * @throws RemoteException if the registry couldn't be located or created + */ + protected Registry getRegistry( + int registryPort, RMIClientSocketFactory clientSocketFactory, RMIServerSocketFactory serverSocketFactory) + throws RemoteException { + + if (clientSocketFactory != null) { + if (this.alwaysCreateRegistry) { + logger.info("Creating new RMI registry"); + return LocateRegistry.createRegistry(registryPort, clientSocketFactory, serverSocketFactory); + } + if (logger.isInfoEnabled()) { + logger.info("Looking for RMI registry at port '" + registryPort + "', using custom socket factory"); + } + try { + // Retrieve existing registry. + Registry reg = LocateRegistry.getRegistry(null, registryPort, clientSocketFactory); + testRegistry(reg); + return reg; + } + catch (RemoteException ex) { + logger.debug("RMI registry access threw exception", ex); + logger.info("Could not detect RMI registry - creating new one"); + // Assume no registry found -> create new one. + return LocateRegistry.createRegistry(registryPort, clientSocketFactory, serverSocketFactory); + } + } + + else { + return getRegistry(registryPort); + } + } + + /** + * Locate or create the RMI registry for this exporter. + * @param registryPort the registry port to use + * @return the RMI registry + * @throws RemoteException if the registry couldn't be located or created + */ + protected Registry getRegistry(int registryPort) throws RemoteException { + if (this.alwaysCreateRegistry) { + logger.info("Creating new RMI registry"); + return LocateRegistry.createRegistry(registryPort); + } + if (logger.isInfoEnabled()) { + logger.info("Looking for RMI registry at port '" + registryPort + "'"); + } + try { + // Retrieve existing registry. + Registry reg = LocateRegistry.getRegistry(registryPort); + testRegistry(reg); + return reg; + } + catch (RemoteException ex) { + logger.debug("RMI registry access threw exception", ex); + logger.info("Could not detect RMI registry - creating new one"); + // Assume no registry found -> create new one. + return LocateRegistry.createRegistry(registryPort); + } + } + + /** + * Test the given RMI registry, calling some operation on it to + * check whether it is still active. + *

Default implementation calls Registry.list(). + * @param registry the RMI registry to test + * @throws RemoteException if thrown by registry methods + * @see java.rmi.registry.Registry#list() + */ + protected void testRegistry(Registry registry) throws RemoteException { + registry.list(); + } + + + /** + * Unbind the RMI service from the registry on bean factory shutdown. + */ + public void destroy() throws RemoteException { + if (logger.isInfoEnabled()) { + logger.info("Unbinding RMI service '" + this.serviceName + + "' from registry at port '" + this.registryPort + "'"); + } + try { + this.registry.unbind(this.serviceName); + } + catch (NotBoundException ex) { + if (logger.isWarnEnabled()) { + logger.warn("RMI service '" + this.serviceName + "' is not bound to registry at port '" + + this.registryPort + "' anymore", ex); + } + } + finally { + unexportObjectSilently(); + } + } + + /** + * Unexport the registered RMI object, logging any exception that arises. + */ + private void unexportObjectSilently() { + try { + UnicastRemoteObject.unexportObject(this.exportedObject, true); + } + catch (NoSuchObjectException ex) { + if (logger.isWarnEnabled()) { + logger.warn("RMI object for service '" + this.serviceName + "' isn't exported anymore", ex); + } + } + } + +} Index: 3rdParty_sources/spring/org/springframework/remoting/rmi/package.html =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/remoting/rmi/package.html,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/remoting/rmi/package.html 17 Aug 2012 15:16:15 -0000 1.1 @@ -0,0 +1,9 @@ + + + +Remoting classes for conventional RMI and transparent remoting via +RMI invokers. Provides a proxy factory for accessing RMI services, +and an exporter for making beans available to RMI clients. + + + Index: 3rdParty_sources/spring/org/springframework/remoting/soap/SoapFaultException.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/remoting/soap/SoapFaultException.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/remoting/soap/SoapFaultException.java 17 Aug 2012 15:16:16 -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.remoting.soap; + +import javax.xml.namespace.QName; + +import org.springframework.remoting.RemoteInvocationFailureException; + +/** + * RemoteInvocationFailureException subclass that provides the details + * of a SOAP fault. + * + * @author Juergen Hoeller + * @since 2.5 + * @see javax.xml.rpc.soap.SOAPFaultException + * @see javax.xml.ws.soap.SOAPFaultException + */ +public abstract class SoapFaultException extends RemoteInvocationFailureException { + + /** + * Constructor for SoapFaultException. + * @param msg the detail message + * @param cause the root cause from the SOAP API in use + */ + protected SoapFaultException(String msg, Throwable cause) { + super(msg, cause); + } + + + /** + * Return the SOAP fault code. + */ + public abstract String getFaultCode(); + + /** + * Return the SOAP fault code as a QName object. + */ + public abstract QName getFaultCodeAsQName(); + + /** + * Return the descriptive SOAP fault string. + */ + public abstract String getFaultString(); + + /** + * Return the actor that caused this fault. + */ + public abstract String getFaultActor(); + +} Index: 3rdParty_sources/spring/org/springframework/remoting/soap/package.html =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/remoting/soap/package.html,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/remoting/soap/package.html 17 Aug 2012 15:16:16 -0000 1.1 @@ -0,0 +1,7 @@ + + + +SOAP-specific exceptions and support classes for Spring's remoting subsystem. + + + Index: 3rdParty_sources/spring/org/springframework/remoting/support/DefaultRemoteInvocationExecutor.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/remoting/support/DefaultRemoteInvocationExecutor.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/remoting/support/DefaultRemoteInvocationExecutor.java 17 Aug 2012 15:16:16 -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.remoting.support; + +import java.lang.reflect.InvocationTargetException; + +import org.springframework.util.Assert; + +/** + * Default implementation of the {@link RemoteInvocationExecutor} interface. + * Simply delegates to {@link RemoteInvocation}'s invoke method. + * + * @author Juergen Hoeller + * @since 1.1 + * @see RemoteInvocation#invoke + */ +public class DefaultRemoteInvocationExecutor implements RemoteInvocationExecutor { + + public Object invoke(RemoteInvocation invocation, Object targetObject) + throws NoSuchMethodException, IllegalAccessException, InvocationTargetException{ + + Assert.notNull(invocation, "RemoteInvocation must not be null"); + Assert.notNull(targetObject, "Target object must not be null"); + return invocation.invoke(targetObject); + } + +} Index: 3rdParty_sources/spring/org/springframework/remoting/support/DefaultRemoteInvocationFactory.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/remoting/support/DefaultRemoteInvocationFactory.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/remoting/support/DefaultRemoteInvocationFactory.java 17 Aug 2012 15:16:16 -0000 1.1 @@ -0,0 +1,34 @@ +/* + * 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.remoting.support; + +import org.aopalliance.intercept.MethodInvocation; + +/** + * Default implementation of the {@link RemoteInvocationFactory} interface. + * Simply creates a new standard {@link RemoteInvocation} object. + * + * @author Juergen Hoeller + * @since 1.1 + */ +public class DefaultRemoteInvocationFactory implements RemoteInvocationFactory { + + public RemoteInvocation createRemoteInvocation(MethodInvocation methodInvocation) { + return new RemoteInvocation(methodInvocation); + } + +} Index: 3rdParty_sources/spring/org/springframework/remoting/support/RemoteAccessor.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/remoting/support/RemoteAccessor.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/remoting/support/RemoteAccessor.java 17 Aug 2012 15:16:16 -0000 1.1 @@ -0,0 +1,62 @@ +/* + * 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.remoting.support; + +/** + * Abstract base class for classes that access a remote service. + * Provides a "serviceInterface" bean property. + * + *

Note that the service interface being used will show some signs of + * remotability, like the granularity of method calls that it offers. + * Furthermore, it has to have serializable arguments etc. + * + *

Accessors are supposed to throw Spring's generic + * {@link org.springframework.remoting.RemoteAccessException} in case + * of remote invocation failure, provided that the service interface + * does not declare java.rmi.RemoteException. + * + * @author Juergen Hoeller + * @since 13.05.2003 + * @see org.springframework.remoting.RemoteAccessException + * @see java.rmi.RemoteException + */ +public abstract class RemoteAccessor extends RemotingSupport { + + private Class serviceInterface; + + + /** + * Set the interface of the service to access. + * The interface must be suitable for the particular service and remoting strategy. + *

Typically required to be able to create a suitable service proxy, + * but can also be optional if the lookup returns a typed proxy. + */ + public void setServiceInterface(Class serviceInterface) { + if (serviceInterface != null && !serviceInterface.isInterface()) { + throw new IllegalArgumentException("'serviceInterface' must be an interface"); + } + this.serviceInterface = serviceInterface; + } + + /** + * Return the interface of the service to access. + */ + public Class getServiceInterface() { + return this.serviceInterface; + } + +} Index: 3rdParty_sources/spring/org/springframework/remoting/support/RemoteExporter.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/remoting/support/RemoteExporter.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/remoting/support/RemoteExporter.java 17 Aug 2012 15:16:16 -0000 1.1 @@ -0,0 +1,185 @@ +/* + * 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.remoting.support; + +import org.springframework.aop.framework.ProxyFactory; +import org.springframework.aop.framework.adapter.AdvisorAdapterRegistry; +import org.springframework.aop.framework.adapter.GlobalAdvisorAdapterRegistry; +import org.springframework.util.ClassUtils; + +/** + * Abstract base class for classes that export a remote service. + * Provides "service" and "serviceInterface" bean properties. + * + *

Note that the service interface being used will show some signs of + * remotability, like the granularity of method calls that it offers. + * Furthermore, it has to have serializable arguments etc. + * + * @author Juergen Hoeller + * @since 26.12.2003 + */ +public abstract class RemoteExporter extends RemotingSupport { + + private Object service; + + private Class serviceInterface; + + private Boolean registerTraceInterceptor; + + private Object[] interceptors; + + + /** + * Set the service to export. + * Typically populated via a bean reference. + */ + public void setService(Object service) { + this.service = service; + } + + /** + * Return the service to export. + */ + public Object getService() { + return this.service; + } + + /** + * Set the interface of the service to export. + * The interface must be suitable for the particular service and remoting strategy. + */ + public void setServiceInterface(Class serviceInterface) { + if (serviceInterface != null && !serviceInterface.isInterface()) { + throw new IllegalArgumentException("'serviceInterface' must be an interface"); + } + this.serviceInterface = serviceInterface; + } + + /** + * Return the interface of the service to export. + */ + public Class getServiceInterface() { + return this.serviceInterface; + } + + /** + * Set whether to register a RemoteInvocationTraceInterceptor for exported + * services. Only applied when a subclass uses getProxyForService + * for creating the proxy to expose. + *

Default is "true". RemoteInvocationTraceInterceptor's most important value + * is that it logs exception stacktraces on the server, before propagating an + * exception to the client. Note that RemoteInvocationTraceInterceptor will not + * be registered by default if the "interceptors" property has been specified. + * @see #setInterceptors + * @see #getProxyForService + * @see RemoteInvocationTraceInterceptor + */ + public void setRegisterTraceInterceptor(boolean registerTraceInterceptor) { + this.registerTraceInterceptor = Boolean.valueOf(registerTraceInterceptor); + } + + /** + * Set additional interceptors (or advisors) to be applied before the + * remote endpoint, e.g. a PerformanceMonitorInterceptor. + *

You may specify any AOP Alliance MethodInterceptors or other + * Spring AOP Advices, as well as Spring AOP Advisors. + * @see #getProxyForService + * @see org.springframework.aop.interceptor.PerformanceMonitorInterceptor + */ + public void setInterceptors(Object[] interceptors) { + this.interceptors = interceptors; + } + + + /** + * Check whether the service reference has been set. + * @see #setService + */ + protected void checkService() throws IllegalArgumentException { + if (getService() == null) { + throw new IllegalArgumentException("Property 'service' is required"); + } + } + + /** + * Check whether a service reference has been set, + * and whether it matches the specified service. + * @see #setServiceInterface + * @see #setService + */ + protected void checkServiceInterface() throws IllegalArgumentException { + Class serviceInterface = getServiceInterface(); + Object service = getService(); + if (serviceInterface == null) { + throw new IllegalArgumentException("Property 'serviceInterface' is required"); + } + if (service instanceof String) { + throw new IllegalArgumentException("Service [" + service + "] is a String " + + "rather than an actual service reference: Have you accidentally specified " + + "the service bean name as value instead of as reference?"); + } + if (!serviceInterface.isInstance(service)) { + throw new IllegalArgumentException("Service interface [" + serviceInterface.getName() + + "] needs to be implemented by service [" + service + "] of class [" + + service.getClass().getName() + "]"); + } + } + + /** + * Get a proxy for the given service object, implementing the specified + * service interface. + *

Used to export a proxy that does not expose any internals but just + * a specific interface intended for remote access. Furthermore, a + * {@link RemoteInvocationTraceInterceptor} will be registered (by default). + * @return the proxy + * @see #setServiceInterface + * @see #setRegisterTraceInterceptor + * @see RemoteInvocationTraceInterceptor + */ + protected Object getProxyForService() { + checkService(); + checkServiceInterface(); + ProxyFactory proxyFactory = new ProxyFactory(); + proxyFactory.addInterface(getServiceInterface()); + if (this.registerTraceInterceptor != null ? + this.registerTraceInterceptor.booleanValue() : this.interceptors == null) { + proxyFactory.addAdvice(new RemoteInvocationTraceInterceptor(getExporterName())); + } + if (this.interceptors != null) { + AdvisorAdapterRegistry adapterRegistry = GlobalAdvisorAdapterRegistry.getInstance(); + for (int i = 0; i < this.interceptors.length; i++) { + proxyFactory.addAdvisor(adapterRegistry.wrap(this.interceptors[i])); + } + } + proxyFactory.setTarget(getService()); + return proxyFactory.getProxy(getBeanClassLoader()); + } + + /** + * Return a short name for this exporter. + * Used for tracing of remote invocations. + *

Default is the unqualified class name (without package). + * Can be overridden in subclasses. + * @see #getProxyForService + * @see RemoteInvocationTraceInterceptor + * @see org.springframework.util.ClassUtils#getShortName + */ + protected String getExporterName() { + return ClassUtils.getShortName(getClass()); + } + +} Index: 3rdParty_sources/spring/org/springframework/remoting/support/RemoteInvocation.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/remoting/support/RemoteInvocation.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/remoting/support/RemoteInvocation.java 17 Aug 2012 15:16:16 -0000 1.1 @@ -0,0 +1,214 @@ +/* + * 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.remoting.support; + +import java.io.Serializable; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.Map; + +import org.aopalliance.intercept.MethodInvocation; + +import org.springframework.util.ClassUtils; + +/** + * Encapsulates a remote invocation, providing core method invocation properties + * in a serializable fashion. Used for RMI and HTTP-based serialization invokers. + * + *

This is an SPI class, typically not used directly by applications. + * Can be subclassed for additional invocation parameters. + * + * @author Juergen Hoeller + * @since 25.02.2004 + * @see RemoteInvocationResult + * @see RemoteInvocationFactory + * @see RemoteInvocationExecutor + * @see org.springframework.remoting.rmi.RmiProxyFactoryBean + * @see org.springframework.remoting.rmi.RmiServiceExporter + * @see org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean + * @see org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter + */ +public class RemoteInvocation implements Serializable { + + /** use serialVersionUID from Spring 1.1 for interoperability */ + private static final long serialVersionUID = 6876024250231820554L; + + + private String methodName; + + private Class[] parameterTypes; + + private Object[] arguments; + + private Map attributes; + + + /** + * Create a new RemoteInvocation for use as JavaBean. + */ + public RemoteInvocation() { + } + + /** + * Create a new RemoteInvocation for the given parameters. + * @param methodName the name of the method to invoke + * @param parameterTypes the parameter types of the method + * @param arguments the arguments for the invocation + */ + public RemoteInvocation(String methodName, Class[] parameterTypes, Object[] arguments) { + this.methodName = methodName; + this.parameterTypes = parameterTypes; + this.arguments = arguments; + } + + /** + * Create a new RemoteInvocation for the given AOP method invocation. + * @param methodInvocation the AOP invocation to convert + */ + public RemoteInvocation(MethodInvocation methodInvocation) { + this.methodName = methodInvocation.getMethod().getName(); + this.parameterTypes = methodInvocation.getMethod().getParameterTypes(); + this.arguments = methodInvocation.getArguments(); + } + + + /** + * Set the name of the target method. + */ + public void setMethodName(String methodName) { + this.methodName = methodName; + } + + /** + * Return the name of the target method. + */ + public String getMethodName() { + return this.methodName; + } + + /** + * Set the parameter types of the target method. + */ + public void setParameterTypes(Class[] parameterTypes) { + this.parameterTypes = parameterTypes; + } + + /** + * Return the parameter types of the target method. + */ + public Class[] getParameterTypes() { + return this.parameterTypes; + } + + /** + * Set the arguments for the target method call. + */ + public void setArguments(Object[] arguments) { + this.arguments = arguments; + } + + /** + * Return the arguments for the target method call. + */ + public Object[] getArguments() { + return this.arguments; + } + + + /** + * Add an additional invocation attribute. Useful to add additional + * invocation context without having to subclass RemoteInvocation. + *

Attribute keys have to be unique, and no overriding of existing + * attributes is allowed. + *

The implementation avoids to unnecessarily create the attributes + * Map, to minimize serialization size. + * @param key the attribute key + * @param value the attribute value + * @throws IllegalStateException if the key is already bound + */ + public void addAttribute(String key, Serializable value) throws IllegalStateException { + if (this.attributes == null) { + this.attributes = new HashMap(); + } + if (this.attributes.containsKey(key)) { + throw new IllegalStateException("There is already an attribute with key '" + key + "' bound"); + } + this.attributes.put(key, value); + } + + /** + * Retrieve the attribute for the given key, if any. + *

The implementation avoids to unnecessarily create the attributes + * Map, to minimize serialization size. + * @param key the attribute key + * @return the attribute value, or null if not defined + */ + public Serializable getAttribute(String key) { + if (this.attributes == null) { + return null; + } + return (Serializable) this.attributes.get(key); + } + + /** + * Set the attributes Map. Only here for special purposes: + * Preferably, use {@link #addAttribute} and {@link #getAttribute}. + * @param attributes the attributes Map + * @see #addAttribute + * @see #getAttribute + */ + public void setAttributes(Map attributes) { + this.attributes = attributes; + } + + /** + * Return the attributes Map. Mainly here for debugging purposes: + * Preferably, use {@link #addAttribute} and {@link #getAttribute}. + * @return the attributes Map, or null if none created + * @see #addAttribute + * @see #getAttribute + */ + public Map getAttributes() { + return this.attributes; + } + + + /** + * Perform this invocation on the given target object. + * Typically called when a RemoteInvocation is received on the server. + * @param targetObject the target object to apply the invocation to + * @return the invocation result + * @throws NoSuchMethodException if the method name could not be resolved + * @throws IllegalAccessException if the method could not be accessed + * @throws InvocationTargetException if the method invocation resulted in an exception + * @see java.lang.reflect.Method#invoke + */ + public Object invoke(Object targetObject) + throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { + + Method method = targetObject.getClass().getMethod(this.methodName, this.parameterTypes); + return method.invoke(targetObject, this.arguments); + } + + + public String toString() { + return "RemoteInvocation: method name '" + this.methodName + "'; parameter types " + + ClassUtils.classNamesToString(this.parameterTypes); + } + +} Index: 3rdParty_sources/spring/org/springframework/remoting/support/RemoteInvocationBasedAccessor.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/remoting/support/RemoteInvocationBasedAccessor.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/remoting/support/RemoteInvocationBasedAccessor.java 17 Aug 2012 15:16:16 -0000 1.1 @@ -0,0 +1,88 @@ +/* + * 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.remoting.support; + +import org.aopalliance.intercept.MethodInvocation; + +/** + * Abstract base class for remote service accessors that are based + * on serialization of {@link RemoteInvocation} objects. + * + * Provides a "remoteInvocationFactory" property, with a + * {@link DefaultRemoteInvocationFactory} as default strategy. + * + * @author Juergen Hoeller + * @since 1.1 + * @see #setRemoteInvocationFactory + * @see RemoteInvocation + * @see RemoteInvocationFactory + * @see DefaultRemoteInvocationFactory + */ +public abstract class RemoteInvocationBasedAccessor extends UrlBasedRemoteAccessor { + + private RemoteInvocationFactory remoteInvocationFactory = new DefaultRemoteInvocationFactory(); + + + /** + * Set the RemoteInvocationFactory to use for this accessor. + * Default is a {@link 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()); + } + + /** + * Return the RemoteInvocationFactory used by this accessor. + */ + public RemoteInvocationFactory getRemoteInvocationFactory() { + return this.remoteInvocationFactory; + } + + /** + * Create a new RemoteInvocation object for the given AOP method invocation. + *

The default implementation delegates to the configured + * {@link #setRemoteInvocationFactory RemoteInvocationFactory}. + * This can be overridden in subclasses in order to provide custom RemoteInvocation + * subclasses, containing additional invocation parameters (e.g. user credentials). + *

Note that it is preferable to build a custom RemoteInvocationFactory + * as a reusable strategy, instead of overriding this method. + * @param methodInvocation the current AOP method invocation + * @return the RemoteInvocation object + * @see RemoteInvocationFactory#createRemoteInvocation + */ + protected RemoteInvocation createRemoteInvocation(MethodInvocation methodInvocation) { + return getRemoteInvocationFactory().createRemoteInvocation(methodInvocation); + } + + /** + * Recreate the invocation result contained in the given RemoteInvocationResult object. + *

The default implementation calls the default recreate() method. + * This 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 RemoteInvocationResult#recreate() + */ + protected Object recreateRemoteInvocationResult(RemoteInvocationResult result) throws Throwable { + return result.recreate(); + } + +} Index: 3rdParty_sources/spring/org/springframework/remoting/support/RemoteInvocationBasedExporter.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/remoting/support/RemoteInvocationBasedExporter.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/remoting/support/RemoteInvocationBasedExporter.java 17 Aug 2012 15:16:16 -0000 1.1 @@ -0,0 +1,122 @@ +/* + * 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.remoting.support; + +import java.lang.reflect.InvocationTargetException; + +/** + * Abstract base class for remote service exporters that are based + * on deserialization of {@link RemoteInvocation} objects. + * + *

Provides a "remoteInvocationExecutor" property, with a + * {@link DefaultRemoteInvocationExecutor} as default strategy. + * + * @author Juergen Hoeller + * @since 1.1 + * @see RemoteInvocationExecutor + * @see DefaultRemoteInvocationExecutor + */ +public abstract class RemoteInvocationBasedExporter extends RemoteExporter { + + private RemoteInvocationExecutor remoteInvocationExecutor = new DefaultRemoteInvocationExecutor(); + + + /** + * Set the RemoteInvocationExecutor to use for this exporter. + * Default is a DefaultRemoteInvocationExecutor. + *

A custom invocation executor can extract further context information + * from the invocation, for example user credentials. + */ + public void setRemoteInvocationExecutor(RemoteInvocationExecutor remoteInvocationExecutor) { + this.remoteInvocationExecutor = remoteInvocationExecutor; + } + + /** + * Return the RemoteInvocationExecutor used by this exporter. + */ + public RemoteInvocationExecutor getRemoteInvocationExecutor() { + return this.remoteInvocationExecutor; + } + + + /** + * Apply the given remote invocation to the given target object. + * The default implementation delegates to the RemoteInvocationExecutor. + *

Can be overridden in subclasses for custom invocation behavior, + * possibly for applying additional invocation parameters from a + * custom RemoteInvocation subclass. Note that it is preferable to use + * a custom RemoteInvocationExecutor which is a reusable strategy. + * @param invocation the remote invocation + * @param targetObject the target object to apply the invocation to + * @return the invocation result + * @throws NoSuchMethodException if the method name could not be resolved + * @throws IllegalAccessException if the method could not be accessed + * @throws InvocationTargetException if the method invocation resulted in an exception + * @see RemoteInvocationExecutor#invoke + */ + protected Object invoke(RemoteInvocation invocation, Object targetObject) + throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { + + if (logger.isTraceEnabled()) { + logger.trace("Executing " + invocation); + } + try { + return getRemoteInvocationExecutor().invoke(invocation, targetObject); + } + catch (NoSuchMethodException ex) { + if (logger.isDebugEnabled()) { + logger.warn("Could not find target method for " + invocation, ex); + } + throw ex; + } + catch (IllegalAccessException ex) { + if (logger.isDebugEnabled()) { + logger.warn("Could not access target method for " + invocation, ex); + } + throw ex; + } + catch (InvocationTargetException ex) { + if (logger.isDebugEnabled()) { + logger.debug("Target method failed for " + invocation, ex.getTargetException()); + } + throw ex; + } + } + + /** + * Apply the given remote invocation to the given target object, wrapping + * the invocation result in a serializable RemoteInvocationResult object. + * The default implementation creates a plain RemoteInvocationResult. + *

Can be overridden in subclasses for custom invocation behavior, + * for example to return additional context information. Note that this + * is not covered by the RemoteInvocationExecutor strategy! + * @param invocation the remote invocation + * @param targetObject the target object to apply the invocation to + * @return the invocation result + * @see #invoke + */ + protected RemoteInvocationResult invokeAndCreateResult(RemoteInvocation invocation, Object targetObject) { + try { + Object value = invoke(invocation, targetObject); + return new RemoteInvocationResult(value); + } + catch (Throwable ex) { + return new RemoteInvocationResult(ex); + } + } + +} Index: 3rdParty_sources/spring/org/springframework/remoting/support/RemoteInvocationExecutor.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/remoting/support/RemoteInvocationExecutor.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/remoting/support/RemoteInvocationExecutor.java 17 Aug 2012 15:16:16 -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.remoting.support; + +import java.lang.reflect.InvocationTargetException; + +/** + * Strategy interface for executing a {@link RemoteInvocation} on a target object. + * + *

Used by {@link org.springframework.remoting.rmi.RmiServiceExporter} (for RMI invokers) + * and by {@link org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter}. + * + * @author Juergen Hoeller + * @since 1.1 + * @see DefaultRemoteInvocationFactory + * @see org.springframework.remoting.rmi.RmiServiceExporter#setRemoteInvocationExecutor + * @see org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter#setRemoteInvocationExecutor + */ +public interface RemoteInvocationExecutor { + + /** + * Perform this invocation on the given target object. + * Typically called when a RemoteInvocation is received on the server. + * @param invocation the RemoteInvocation + * @param targetObject the target object to apply the invocation to + * @return the invocation result + * @throws NoSuchMethodException if the method name could not be resolved + * @throws IllegalAccessException if the method could not be accessed + * @throws InvocationTargetException if the method invocation resulted in an exception + * @see java.lang.reflect.Method#invoke + */ + Object invoke(RemoteInvocation invocation, Object targetObject) + throws NoSuchMethodException, IllegalAccessException, InvocationTargetException; + +} Index: 3rdParty_sources/spring/org/springframework/remoting/support/RemoteInvocationFactory.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/remoting/support/RemoteInvocationFactory.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/remoting/support/RemoteInvocationFactory.java 17 Aug 2012 15:16:16 -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.remoting.support; + +import org.aopalliance.intercept.MethodInvocation; + +/** + * Strategy interface for creating a {@link RemoteInvocation} from an AOP Alliance + * {@link org.aopalliance.intercept.MethodInvocation}. + * + *

Used by {@link org.springframework.remoting.rmi.RmiClientInterceptor} (for RMI invokers) + * and by {@link org.springframework.remoting.httpinvoker.HttpInvokerClientInterceptor}. + * + * @author Juergen Hoeller + * @since 1.1 + * @see DefaultRemoteInvocationFactory + * @see org.springframework.remoting.rmi.RmiClientInterceptor#setRemoteInvocationFactory + * @see org.springframework.remoting.httpinvoker.HttpInvokerClientInterceptor#setRemoteInvocationFactory + */ +public interface RemoteInvocationFactory { + + /** + * Create a serializable RemoteInvocation object from the given AOP + * MethodInvocation. + *

Can be implemented to add custom context information to the + * remote invocation, for example user credentials. + * @param methodInvocation the original AOP MethodInvocation object + * @return the RemoteInvocation object + */ + RemoteInvocation createRemoteInvocation(MethodInvocation methodInvocation); + +} Index: 3rdParty_sources/spring/org/springframework/remoting/support/RemoteInvocationResult.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/remoting/support/RemoteInvocationResult.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/remoting/support/RemoteInvocationResult.java 17 Aug 2012 15:16:16 -0000 1.1 @@ -0,0 +1,123 @@ +/* + * 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.remoting.support; + +import java.io.Serializable; +import java.lang.reflect.InvocationTargetException; + +/** + * Encapsulates a remote invocation result, holding a result value or an exception. + * Used for HTTP-based serialization invokers. + * + *

This is an SPI class, typically not used directly by applications. + * Can be subclassed for additional invocation parameters. + * + * @author Juergen Hoeller + * @since 1.1 + * @see RemoteInvocation + */ +public class RemoteInvocationResult implements Serializable { + + /** Use serialVersionUID from Spring 1.1 for interoperability */ + private static final long serialVersionUID = 2138555143707773549L; + + + private Object value; + + private Throwable exception; + + + /** + * Create a new RemoteInvocationResult for the given result value. + * @param value the result value returned by a successful invocation + * of the target method + */ + public RemoteInvocationResult(Object value) { + this.value = value; + } + + /** + * Create a new RemoteInvocationResult for the given exception. + * @param exception the exception thrown by an unsuccessful invocation + * of the target method + */ + public RemoteInvocationResult(Throwable exception) { + this.exception = exception; + } + + + /** + * Return the result value returned by a successful invocation + * of the target method, if any. + * @see #hasException + */ + public Object getValue() { + return this.value; + } + + /** + * Return the exception thrown by an unsuccessful invocation + * of the target method, if any. + * @see #hasException + */ + public Throwable getException() { + return this.exception; + } + + /** + * Return whether this invocation result holds an exception. + * If this returns false, the result value applies + * (even if null). + * @see #getValue + * @see #getException + */ + public boolean hasException() { + return (this.exception != null); + } + + /** + * Return whether this invocation result holds an InvocationTargetException, + * thrown by an invocation of the target method itself. + * @see #hasException() + */ + public boolean hasInvocationTargetException() { + return (this.exception instanceof InvocationTargetException); + } + + + /** + * Recreate the invocation result, either returning the result value + * in case of a successful invocation of the target method, or + * rethrowing the exception thrown by the target method. + * @return the result value, if any + * @throws Throwable the exception, if any + */ + public Object recreate() throws Throwable { + if (this.exception != null) { + Throwable exToThrow = this.exception; + if (this.exception instanceof InvocationTargetException) { + exToThrow = ((InvocationTargetException) this.exception).getTargetException(); + } + RemoteInvocationUtils.fillInClientStackTraceIfPossible(exToThrow); + throw exToThrow; + } + else { + return this.value; + } + } + +} Index: 3rdParty_sources/spring/org/springframework/remoting/support/RemoteInvocationTraceInterceptor.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/remoting/support/RemoteInvocationTraceInterceptor.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/remoting/support/RemoteInvocationTraceInterceptor.java 17 Aug 2012 15:16:16 -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.remoting.support; + +import java.lang.reflect.Method; + +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.util.ClassUtils; + +/** + * AOP Alliance MethodInterceptor for tracing remote invocations. + * Automatically applied by RemoteExporter and its subclasses. + * + *

Logs an incoming remote call as well as the finished processing of a remote call + * at DEBUG level. If the processing of a remote call results in a checked exception, + * the exception will get logged at INFO level; if it results in an unchecked + * exception (or error), the exception will get logged at WARN level. + * + *

The logging of exceptions is particularly useful to save the stacktrace + * information on the server-side rather than just propagating the exception + * to the client (who might or might not log it properly). + * + * @author Juergen Hoeller + * @since 1.2 + * @see RemoteExporter#setRegisterTraceInterceptor + * @see RemoteExporter#getProxyForService + */ +public class RemoteInvocationTraceInterceptor implements MethodInterceptor { + + protected static final Log logger = LogFactory.getLog(RemoteInvocationTraceInterceptor.class); + + private final String exporterNameClause; + + + /** + * Create a new RemoteInvocationTraceInterceptor. + */ + public RemoteInvocationTraceInterceptor() { + this.exporterNameClause = ""; + } + + /** + * Create a new RemoteInvocationTraceInterceptor. + * @param exporterName the name of the remote exporter + * (to be used as context information in log messages) + */ + public RemoteInvocationTraceInterceptor(String exporterName) { + this.exporterNameClause = exporterName + " "; + } + + + public Object invoke(MethodInvocation invocation) throws Throwable { + Method method = invocation.getMethod(); + if (logger.isDebugEnabled()) { + logger.debug("Incoming " + this.exporterNameClause + "remote call: " + + ClassUtils.getQualifiedMethodName(method)); + } + try { + Object retVal = invocation.proceed(); + if (logger.isDebugEnabled()) { + logger.debug("Finished processing of " + this.exporterNameClause + "remote call: " + + ClassUtils.getQualifiedMethodName(method)); + } + return retVal; + } + catch (Throwable ex) { + if (ex instanceof RuntimeException || ex instanceof Error) { + if (logger.isWarnEnabled()) { + logger.warn("Processing of " + this.exporterNameClause + "remote call resulted in fatal exception: " + + ClassUtils.getQualifiedMethodName(method), ex); + } + } + else { + if (logger.isInfoEnabled()) { + logger.info("Processing of " + this.exporterNameClause + "remote call resulted in exception: " + + ClassUtils.getQualifiedMethodName(method), ex); + } + } + throw ex; + } + } + +} Index: 3rdParty_sources/spring/org/springframework/remoting/support/RemoteInvocationUtils.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/remoting/support/RemoteInvocationUtils.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/remoting/support/RemoteInvocationUtils.java 17 Aug 2012 15:16:16 -0000 1.1 @@ -0,0 +1,62 @@ +/* + * 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.remoting.support; + +import java.util.HashSet; +import java.util.Set; + +import org.springframework.core.JdkVersion; + +/** + * General utilities for handling remote invocations. + * + *

Mainly intended for use within the remoting framework. + * + * @author Juergen Hoeller + * @since 2.0 + */ +public abstract class RemoteInvocationUtils { + + /** + * Fill the current client-side stack trace into the given exception. + *

The given exception is typically thrown on the server and serialized + * as-is, with the client wanting it to contain the client-side portion + * of the stack trace as well. What we can do here is to update the + * StackTraceElement array with the current client-side stack + * trace, provided that we run on JDK 1.4+. + * @param ex the exception to update + * @see java.lang.Throwable#getStackTrace() + * @see java.lang.Throwable#setStackTrace(StackTraceElement[]) + */ + public static void fillInClientStackTraceIfPossible(Throwable ex) { + if (ex != null) { + StackTraceElement[] clientStack = new Throwable().getStackTrace(); + Set visitedExceptions = new HashSet(); + Throwable exToUpdate = ex; + while (exToUpdate != null && !visitedExceptions.contains(exToUpdate)) { + StackTraceElement[] serverStack = exToUpdate.getStackTrace(); + StackTraceElement[] combinedStack = new StackTraceElement[serverStack.length + clientStack.length]; + System.arraycopy(serverStack, 0, combinedStack, 0, serverStack.length); + System.arraycopy(clientStack, 0, combinedStack, serverStack.length, clientStack.length); + exToUpdate.setStackTrace(combinedStack); + visitedExceptions.add(exToUpdate); + exToUpdate = exToUpdate.getCause(); + } + } + } + +} Index: 3rdParty_sources/spring/org/springframework/remoting/support/RemotingSupport.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/remoting/support/RemotingSupport.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/remoting/support/RemotingSupport.java 17 Aug 2012 15:16:16 -0000 1.1 @@ -0,0 +1,74 @@ +/* + * 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.remoting.support; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import org.springframework.beans.factory.BeanClassLoaderAware; +import org.springframework.util.ClassUtils; + +/** + * Generic support base class for remote accessor and exporters, + * providing common bean ClassLoader handling. + * + * @author Juergen Hoeller + * @since 2.5.2 + */ +public abstract class RemotingSupport implements BeanClassLoaderAware { + + /** Logger available to subclasses */ + protected final Log logger = LogFactory.getLog(getClass()); + + private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader(); + + + public void setBeanClassLoader(ClassLoader classLoader) { + this.beanClassLoader = classLoader; + } + + /** + * Return the ClassLoader that this accessor operates in, + * to be used for deserializing and for generating proxies. + */ + protected ClassLoader getBeanClassLoader() { + return this.beanClassLoader; + } + + + /** + * Override the thread context ClassLoader with the environment's bean ClassLoader + * if necessary, i.e. if the bean ClassLoader is not equivalent to the thread + * context ClassLoader already. + * @return the original thread context ClassLoader, or null if not overridden + */ + protected ClassLoader overrideThreadContextClassLoader() { + return ClassUtils.overrideThreadContextClassLoader(getBeanClassLoader()); + } + + /** + * Reset the original thread context ClassLoader if necessary. + * @param original the original thread context ClassLoader, + * or null if not overridden (and hence nothing to reset) + */ + protected void resetThreadContextClassLoader(ClassLoader original) { + if (original != null) { + Thread.currentThread().setContextClassLoader(original); + } + } + +} Index: 3rdParty_sources/spring/org/springframework/remoting/support/SimpleHttpServerFactoryBean.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/remoting/support/SimpleHttpServerFactoryBean.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/remoting/support/SimpleHttpServerFactoryBean.java 17 Aug 2012 15:16:16 -0000 1.1 @@ -0,0 +1,197 @@ +/* + * 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.remoting.support; + +import java.io.IOException; +import java.net.InetSocketAddress; +import java.util.List; +import java.util.Map; +import java.util.concurrent.Executor; + +import com.sun.net.httpserver.Authenticator; +import com.sun.net.httpserver.Filter; +import com.sun.net.httpserver.HttpContext; +import com.sun.net.httpserver.HttpHandler; +import com.sun.net.httpserver.HttpServer; +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.core.task.TaskExecutor; +import org.springframework.core.task.support.ConcurrentExecutorAdapter; + +/** + * {@link org.springframework.beans.factory.FactoryBean} that creates a simple + * HTTP server, based on the HTTP server that is included in Sun's JRE 1.6. + * Starts the HTTP server on initialization and stops it on destruction. + * Exposes the resulting {@link com.sun.net.httpserver.HttpServer} object. + * + *

Allows for registering {@link com.sun.net.httpserver.HttpHandler HttpHandlers} + * for specific {@link #setContexts context paths}. Alternatively, + * register such context-specific handlers programmatically on the + * {@link com.sun.net.httpserver.HttpServer} itself. + * + * @author Juergen Hoeller + * @author Arjen Poutsma + * @since 2.5.1 + * @see #setPort + * @see #setContexts + */ +public class SimpleHttpServerFactoryBean implements FactoryBean, InitializingBean, DisposableBean { + + protected final Log logger = LogFactory.getLog(getClass()); + + private int port = 8080; + + private String hostname; + + private int backlog = -1; + + private int shutdownDelay = 0; + + private Executor executor; + + private Map contexts; + + private List filters; + + private Authenticator authenticator; + + private HttpServer server; + + + /** + * Specify the HTTP server's port. Default is 8080. + */ + public void setPort(int port) { + this.port = port; + } + + /** + * Specify the HTTP server's hostname to bind to. Default is localhost; + * can be overridden with a specific network address to bind to. + */ + public void setHostname(String hostname) { + this.hostname = hostname; + } + + /** + * Specify the HTTP server's TCP backlog. Default is -1, + * indicating the system's default value. + */ + public void setBacklog(int backlog) { + this.backlog = backlog; + } + + /** + * Specify the number of seconds to wait until HTTP exchanges have + * completed when shutting down the HTTP server. Default is 0. + */ + public void setShutdownDelay(int shutdownDelay) { + this.shutdownDelay = shutdownDelay; + } + + /** + * Set the JDK concurrent executor to use for dispatching incoming requests. + * @see com.sun.net.httpserver.HttpServer#setExecutor + */ + public void setExecutor(Executor executor) { + this.executor = executor; + } + + /** + * Set the Spring TaskExecutor to use for dispatching incoming requests. + * @see com.sun.net.httpserver.HttpServer#setExecutor + */ + public void setTaskExecutor(TaskExecutor executor) { + this.executor = new ConcurrentExecutorAdapter(executor); + } + + /** + * Register {@link com.sun.net.httpserver.HttpHandler HttpHandlers} + * for specific context paths. + * @param contexts a Map with context paths as keys and HttpHandler + * objects as values + * @see org.springframework.remoting.httpinvoker.SimpleHttpInvokerServiceExporter + * @see org.springframework.remoting.caucho.SimpleHessianServiceExporter + * @see org.springframework.remoting.caucho.SimpleBurlapServiceExporter + */ + public void setContexts(Map contexts) { + this.contexts = contexts; + } + + /** + * Register common {@link com.sun.net.httpserver.Filter Filters} to be + * applied to all locally registered {@link #setContexts contexts}. + */ + public void setFilters(List filters) { + this.filters = filters; + } + + /** + * Register a common {@link com.sun.net.httpserver.Authenticator} to be + * applied to all locally registered {@link #setContexts contexts}. + */ + public void setAuthenticator(Authenticator authenticator) { + this.authenticator = authenticator; + } + + + public void afterPropertiesSet() throws IOException { + InetSocketAddress address = (this.hostname != null ? + new InetSocketAddress(this.hostname, this.port) : new InetSocketAddress(this.port)); + this.server = HttpServer.create(address, this.backlog); + if (this.executor != null) { + this.server.setExecutor(this.executor); + } + if (this.contexts != null) { + for (String key : this.contexts.keySet()) { + HttpContext httpContext = this.server.createContext(key, this.contexts.get(key)); + if (this.filters != null) { + httpContext.getFilters().addAll(this.filters); + } + if (this.authenticator != null) { + httpContext.setAuthenticator(this.authenticator); + } + } + } + if (this.logger.isInfoEnabled()) { + this.logger.info("Starting HttpServer at address " + address); + } + this.server.start(); + } + + public Object getObject() { + return this.server; + } + + public Class getObjectType() { + return (this.server != null ? this.server.getClass() : HttpServer.class); + } + + public boolean isSingleton() { + return true; + } + + public void destroy() { + logger.info("Stopping HttpServer"); + this.server.stop(this.shutdownDelay); + } + +} Index: 3rdParty_sources/spring/org/springframework/remoting/support/UrlBasedRemoteAccessor.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/remoting/support/UrlBasedRemoteAccessor.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/remoting/support/UrlBasedRemoteAccessor.java 17 Aug 2012 15:16:16 -0000 1.1 @@ -0,0 +1,55 @@ +/* + * 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.remoting.support; + +import org.springframework.beans.factory.InitializingBean; + +/** + * Abstract base class for classes that access remote services via URLs. + * Provides a "serviceUrl" bean property, which is considered as required. + * + * @author Juergen Hoeller + * @since 15.12.2003 + */ +public abstract class UrlBasedRemoteAccessor extends RemoteAccessor implements InitializingBean { + + private String serviceUrl; + + + /** + * Set the URL of this remote accessor's target service. + * The URL must be compatible with the rules of the particular remoting provider. + */ + public void setServiceUrl(String serviceUrl) { + this.serviceUrl = serviceUrl; + } + + /** + * Return the URL of this remote accessor's target service. + */ + public String getServiceUrl() { + return this.serviceUrl; + } + + + public void afterPropertiesSet() { + if (getServiceUrl() == null) { + throw new IllegalArgumentException("Property 'serviceUrl' is required"); + } + } + +} Index: 3rdParty_sources/spring/org/springframework/remoting/support/package.html =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/remoting/support/package.html,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/remoting/support/package.html 17 Aug 2012 15:16:16 -0000 1.1 @@ -0,0 +1,8 @@ + + + +Generic support classes for remoting implementations. +Provides abstract base classes for remote proxy factories. + + + Index: 3rdParty_sources/spring/org/springframework/util/AntPathMatcher.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/util/AntPathMatcher.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/util/AntPathMatcher.java 17 Aug 2012 15:16:09 -0000 1.1 @@ -0,0 +1,411 @@ +/* + * 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.util; + +/** + * PathMatcher implementation for Ant-style path patterns. + * Examples are provided below. + * + *

Part of this mapping code has been kindly borrowed from + * Apache Ant. + * + *

The mapping matches URLs using the following rules:
+ *

    + *
  • ? matches one character
  • + *
  • * matches zero or more characters
  • + *
  • ** matches zero or more 'directories' in a path
  • + *
+ * + *

Some examples:
+ *

    + *
  • com/t?st.jsp - matches com/test.jsp but also + * com/tast.jsp or com/txst.jsp
  • + *
  • com/*.jsp - matches all .jsp files in the + * com directory
  • + *
  • com/**/test.jsp - matches all test.jsp + * files underneath the com path
  • + *
  • org/springframework/**/*.jsp - matches all .jsp + * files underneath the org/springframework path
  • + *
  • org/**/servlet/bla.jsp - matches + * org/springframework/servlet/bla.jsp but also + * org/springframework/testing/servlet/bla.jsp and + * org/servlet/bla.jsp
  • + *
+ * + * @author Alef Arendsen + * @author Juergen Hoeller + * @author Rob Harrop + * @since 16.07.2003 + */ +public class AntPathMatcher implements PathMatcher { + + /** Default path separator: "/" */ + public static final String DEFAULT_PATH_SEPARATOR = "/"; + + private String pathSeparator = DEFAULT_PATH_SEPARATOR; + + + /** + * Set the path separator to use for pattern parsing. + * Default is "/", as in Ant. + */ + public void setPathSeparator(String pathSeparator) { + this.pathSeparator = (pathSeparator != null ? pathSeparator : DEFAULT_PATH_SEPARATOR); + } + + + public boolean isPattern(String path) { + return (path.indexOf('*') != -1 || path.indexOf('?') != -1); + } + + public boolean match(String pattern, String path) { + return doMatch(pattern, path, true); + } + + public boolean matchStart(String pattern, String path) { + return doMatch(pattern, path, false); + } + + + /** + * Actually match the given path against the given pattern. + * @param pattern the pattern to match against + * @param path the path String to test + * @param fullMatch whether a full pattern match is required + * (else a pattern match as far as the given base path goes is sufficient) + * @return true if the supplied path matched, + * false if it didn't + */ + protected boolean doMatch(String pattern, String path, boolean fullMatch) { + if (path.startsWith(this.pathSeparator) != pattern.startsWith(this.pathSeparator)) { + return false; + } + + String[] pattDirs = StringUtils.tokenizeToStringArray(pattern, this.pathSeparator); + String[] pathDirs = StringUtils.tokenizeToStringArray(path, this.pathSeparator); + + int pattIdxStart = 0; + int pattIdxEnd = pattDirs.length - 1; + int pathIdxStart = 0; + int pathIdxEnd = pathDirs.length - 1; + + // Match all elements up to the first ** + while (pattIdxStart <= pattIdxEnd && pathIdxStart <= pathIdxEnd) { + String patDir = pattDirs[pattIdxStart]; + if ("**".equals(patDir)) { + break; + } + if (!matchStrings(patDir, pathDirs[pathIdxStart])) { + return false; + } + pattIdxStart++; + pathIdxStart++; + } + + if (pathIdxStart > pathIdxEnd) { + // Path is exhausted, only match if rest of pattern is * or **'s + if (pattIdxStart > pattIdxEnd) { + return (pattern.endsWith(this.pathSeparator) ? + path.endsWith(this.pathSeparator) : !path.endsWith(this.pathSeparator)); + } + if (!fullMatch) { + return true; + } + if (pattIdxStart == pattIdxEnd && pattDirs[pattIdxStart].equals("*") && + path.endsWith(this.pathSeparator)) { + return true; + } + for (int i = pattIdxStart; i <= pattIdxEnd; i++) { + if (!pattDirs[i].equals("**")) { + return false; + } + } + return true; + } + else if (pattIdxStart > pattIdxEnd) { + // String not exhausted, but pattern is. Failure. + return false; + } + else if (!fullMatch && "**".equals(pattDirs[pattIdxStart])) { + // Path start definitely matches due to "**" part in pattern. + return true; + } + + // up to last '**' + while (pattIdxStart <= pattIdxEnd && pathIdxStart <= pathIdxEnd) { + String patDir = pattDirs[pattIdxEnd]; + if (patDir.equals("**")) { + break; + } + if (!matchStrings(patDir, pathDirs[pathIdxEnd])) { + return false; + } + pattIdxEnd--; + pathIdxEnd--; + } + if (pathIdxStart > pathIdxEnd) { + // String is exhausted + for (int i = pattIdxStart; i <= pattIdxEnd; i++) { + if (!pattDirs[i].equals("**")) { + return false; + } + } + return true; + } + + while (pattIdxStart != pattIdxEnd && pathIdxStart <= pathIdxEnd) { + int patIdxTmp = -1; + for (int i = pattIdxStart + 1; i <= pattIdxEnd; i++) { + if (pattDirs[i].equals("**")) { + patIdxTmp = i; + break; + } + } + if (patIdxTmp == pattIdxStart + 1) { + // '**/**' situation, so skip one + pattIdxStart++; + continue; + } + // Find the pattern between padIdxStart & padIdxTmp in str between + // strIdxStart & strIdxEnd + int patLength = (patIdxTmp - pattIdxStart - 1); + int strLength = (pathIdxEnd - pathIdxStart + 1); + int foundIdx = -1; + + strLoop: + for (int i = 0; i <= strLength - patLength; i++) { + for (int j = 0; j < patLength; j++) { + String subPat = (String) pattDirs[pattIdxStart + j + 1]; + String subStr = (String) pathDirs[pathIdxStart + i + j]; + if (!matchStrings(subPat, subStr)) { + continue strLoop; + } + } + foundIdx = pathIdxStart + i; + break; + } + + if (foundIdx == -1) { + return false; + } + + pattIdxStart = patIdxTmp; + pathIdxStart = foundIdx + patLength; + } + + for (int i = pattIdxStart; i <= pattIdxEnd; i++) { + if (!pattDirs[i].equals("**")) { + return false; + } + } + + return true; + } + + /** + * Tests whether or not a string matches against a pattern. + * The pattern may contain two special characters:
+ * '*' means zero or more characters
+ * '?' means one and only one character + * @param pattern pattern to match against. + * Must not be null. + * @param str string which must be matched against the pattern. + * Must not be null. + * @return true if the string matches against the + * pattern, or false otherwise. + */ + private boolean matchStrings(String pattern, String str) { + char[] patArr = pattern.toCharArray(); + char[] strArr = str.toCharArray(); + int patIdxStart = 0; + int patIdxEnd = patArr.length - 1; + int strIdxStart = 0; + int strIdxEnd = strArr.length - 1; + char ch; + + boolean containsStar = false; + for (int i = 0; i < patArr.length; i++) { + if (patArr[i] == '*') { + containsStar = true; + break; + } + } + + if (!containsStar) { + // No '*'s, so we make a shortcut + if (patIdxEnd != strIdxEnd) { + return false; // Pattern and string do not have the same size + } + for (int i = 0; i <= patIdxEnd; i++) { + ch = patArr[i]; + if (ch != '?') { + if (ch != strArr[i]) { + return false;// Character mismatch + } + } + } + return true; // String matches against pattern + } + + + if (patIdxEnd == 0) { + return true; // Pattern contains only '*', which matches anything + } + + // Process characters before first star + while ((ch = patArr[patIdxStart]) != '*' && strIdxStart <= strIdxEnd) { + if (ch != '?') { + if (ch != strArr[strIdxStart]) { + return false;// Character mismatch + } + } + patIdxStart++; + strIdxStart++; + } + if (strIdxStart > strIdxEnd) { + // All characters in the string are used. Check if only '*'s are + // left in the pattern. If so, we succeeded. Otherwise failure. + for (int i = patIdxStart; i <= patIdxEnd; i++) { + if (patArr[i] != '*') { + return false; + } + } + return true; + } + + // Process characters after last star + while ((ch = patArr[patIdxEnd]) != '*' && strIdxStart <= strIdxEnd) { + if (ch != '?') { + if (ch != strArr[strIdxEnd]) { + return false;// Character mismatch + } + } + patIdxEnd--; + strIdxEnd--; + } + if (strIdxStart > strIdxEnd) { + // All characters in the string are used. Check if only '*'s are + // left in the pattern. If so, we succeeded. Otherwise failure. + for (int i = patIdxStart; i <= patIdxEnd; i++) { + if (patArr[i] != '*') { + return false; + } + } + return true; + } + + // process pattern between stars. padIdxStart and patIdxEnd point + // always to a '*'. + while (patIdxStart != patIdxEnd && strIdxStart <= strIdxEnd) { + int patIdxTmp = -1; + for (int i = patIdxStart + 1; i <= patIdxEnd; i++) { + if (patArr[i] == '*') { + patIdxTmp = i; + break; + } + } + if (patIdxTmp == patIdxStart + 1) { + // Two stars next to each other, skip the first one. + patIdxStart++; + continue; + } + // Find the pattern between padIdxStart & padIdxTmp in str between + // strIdxStart & strIdxEnd + int patLength = (patIdxTmp - patIdxStart - 1); + int strLength = (strIdxEnd - strIdxStart + 1); + int foundIdx = -1; + strLoop: + for (int i = 0; i <= strLength - patLength; i++) { + for (int j = 0; j < patLength; j++) { + ch = patArr[patIdxStart + j + 1]; + if (ch != '?') { + if (ch != strArr[strIdxStart + i + j]) { + continue strLoop; + } + } + } + + foundIdx = strIdxStart + i; + break; + } + + if (foundIdx == -1) { + return false; + } + + patIdxStart = patIdxTmp; + strIdxStart = foundIdx + patLength; + } + + // All characters in the string are used. Check if only '*'s are left + // in the pattern. If so, we succeeded. Otherwise failure. + for (int i = patIdxStart; i <= patIdxEnd; i++) { + if (patArr[i] != '*') { + return false; + } + } + + return true; + } + + /** + * Given a pattern and a full path, determine the pattern-mapped part. + *

For example: + *

    + *
  • '/docs/cvs/commit.html' and '/docs/cvs/commit.html -> ''
  • + *
  • '/docs/*' and '/docs/cvs/commit -> 'cvs/commit'
  • + *
  • '/docs/cvs/*.html' and '/docs/cvs/commit.html -> 'commit.html'
  • + *
  • '/docs/**' and '/docs/cvs/commit -> 'cvs/commit'
  • + *
  • '/docs/**\/*.html' and '/docs/cvs/commit.html -> 'cvs/commit.html'
  • + *
  • '/*.html' and '/docs/cvs/commit.html -> 'docs/cvs/commit.html'
  • + *
  • '*.html' and '/docs/cvs/commit.html -> '/docs/cvs/commit.html'
  • + *
  • '*' and '/docs/cvs/commit.html -> '/docs/cvs/commit.html'
  • + *
+ *

Assumes that {@link #match} returns true for 'pattern' + * and 'path', but does not enforce this. + */ + public String extractPathWithinPattern(String pattern, String path) { + String[] patternParts = StringUtils.tokenizeToStringArray(pattern, this.pathSeparator); + String[] pathParts = StringUtils.tokenizeToStringArray(path, this.pathSeparator); + + StringBuffer buffer = new StringBuffer(); + + // Add any path parts that have a wildcarded pattern part. + int puts = 0; + for (int i = 0; i < patternParts.length; i++) { + String patternPart = patternParts[i]; + if ((patternPart.indexOf('*') > -1 || patternPart.indexOf('?') > -1) && pathParts.length >= i + 1) { + if (puts > 0 || (i == 0 && !pattern.startsWith(this.pathSeparator))) { + buffer.append(this.pathSeparator); + } + buffer.append(pathParts[i]); + puts++; + } + } + + // Append any trailing path parts. + for (int i = patternParts.length; i < pathParts.length; i++) { + if (puts > 0 || i > 0) { + buffer.append(this.pathSeparator); + } + buffer.append(pathParts[i]); + } + + return buffer.toString(); + } + +} Index: 3rdParty_sources/spring/org/springframework/util/Assert.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/util/Assert.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/util/Assert.java 17 Aug 2012 15:16:09 -0000 1.1 @@ -0,0 +1,401 @@ +/* + * 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.util; + +import java.util.Collection; +import java.util.Map; + +/** + * Assertion utility class that assists in validating arguments. + * Useful for identifying programmer errors early and clearly at runtime. + * + *

For example, if the contract of a public method states it does not + * allow null arguments, Assert can be used to validate that + * contract. Doing this clearly indicates a contract violation when it + * occurs and protects the class's invariants. + * + *

Typically used to validate method arguments rather than configuration + * properties, to check for cases that are usually programmer errors rather than + * configuration errors. In contrast to config initialization code, there is + * usally no point in falling back to defaults in such methods. + * + *

This class is similar to JUnit's assertion library. If an argument value is + * deemed invalid, an {@link IllegalArgumentException} is thrown (typically). + * For example: + * + *

+ * Assert.notNull(clazz, "The class must not be null");
+ * Assert.isTrue(i > 0, "The value must be greater than zero");
+ * + * Mainly for internal use within the framework; consider Jakarta's Commons Lang + * >= 2.0 for a more comprehensive suite of assertion utilities. + * + * @author Keith Donald + * @author Juergen Hoeller + * @author Colin Sampaleanu + * @author Rob Harrop + * @since 1.1.2 + */ +public abstract class Assert { + + /** + * Assert a boolean expression, throwing IllegalArgumentException + * if the test result is false. + *
Assert.isTrue(i > 0, "The value must be greater than zero");
+ * @param expression a boolean expression + * @param message the exception message to use if the assertion fails + * @throws IllegalArgumentException if expression is false + */ + public static void isTrue(boolean expression, String message) { + if (!expression) { + throw new IllegalArgumentException(message); + } + } + + /** + * Assert a boolean expression, throwing IllegalArgumentException + * if the test result is false. + *
Assert.isTrue(i > 0);
+ * @param expression a boolean expression + * @throws IllegalArgumentException if expression is false + */ + public static void isTrue(boolean expression) { + isTrue(expression, "[Assertion failed] - this expression must be true"); + } + + /** + * Assert that an object is null . + *
Assert.isNull(value, "The value must be null");
+ * @param object the object to check + * @param message the exception message to use if the assertion fails + * @throws IllegalArgumentException if the object is not null + */ + public static void isNull(Object object, String message) { + if (object != null) { + throw new IllegalArgumentException(message); + } + } + + /** + * Assert that an object is null . + *
Assert.isNull(value);
+ * @param object the object to check + * @throws IllegalArgumentException if the object is not null + */ + public static void isNull(Object object) { + isNull(object, "[Assertion failed] - the object argument must be null"); + } + + /** + * Assert that an object is not null . + *
Assert.notNull(clazz, "The class must not be null");
+ * @param object the object to check + * @param message the exception message to use if the assertion fails + * @throws IllegalArgumentException if the object is null + */ + public static void notNull(Object object, String message) { + if (object == null) { + throw new IllegalArgumentException(message); + } + } + + /** + * Assert that an object is not null . + *
Assert.notNull(clazz);
+ * @param object the object to check + * @throws IllegalArgumentException if the object is null + */ + public static void notNull(Object object) { + notNull(object, "[Assertion failed] - this argument is required; it must not be null"); + } + + /** + * Assert that the given String is not empty; that is, + * it must not be null and not the empty String. + *
Assert.hasLength(name, "Name must not be empty");
+ * @param text the String to check + * @param message the exception message to use if the assertion fails + * @see StringUtils#hasLength + */ + public static void hasLength(String text, String message) { + if (!StringUtils.hasLength(text)) { + throw new IllegalArgumentException(message); + } + } + + /** + * Assert that the given String is not empty; that is, + * it must not be null and not the empty String. + *
Assert.hasLength(name);
+ * @param text the String to check + * @see StringUtils#hasLength + */ + public static void hasLength(String text) { + hasLength(text, + "[Assertion failed] - this String argument must have length; it must not be null or empty"); + } + + /** + * Assert that the given String has valid text content; that is, it must not + * be null and must contain at least one non-whitespace character. + *
Assert.hasText(name, "'name' must not be empty");
+ * @param text the String to check + * @param message the exception message to use if the assertion fails + * @see StringUtils#hasText + */ + public static void hasText(String text, String message) { + if (!StringUtils.hasText(text)) { + throw new IllegalArgumentException(message); + } + } + + /** + * Assert that the given String has valid text content; that is, it must not + * be null and must contain at least one non-whitespace character. + *
Assert.hasText(name, "'name' must not be empty");
+ * @param text the String to check + * @see StringUtils#hasText + */ + public static void hasText(String text) { + hasText(text, + "[Assertion failed] - this String argument must have text; it must not be null, empty, or blank"); + } + + /** + * Assert that the given text does not contain the given substring. + *
Assert.doesNotContain(name, "rod", "Name must not contain 'rod'");
+ * @param textToSearch the text to search + * @param substring the substring to find within the text + * @param message the exception message to use if the assertion fails + */ + public static void doesNotContain(String textToSearch, String substring, String message) { + if (StringUtils.hasLength(textToSearch) && StringUtils.hasLength(substring) && + textToSearch.indexOf(substring) != -1) { + throw new IllegalArgumentException(message); + } + } + + /** + * Assert that the given text does not contain the given substring. + *
Assert.doesNotContain(name, "rod");
+ * @param textToSearch the text to search + * @param substring the substring to find within the text + */ + public static void doesNotContain(String textToSearch, String substring) { + doesNotContain(textToSearch, substring, + "[Assertion failed] - this String argument must not contain the substring [" + substring + "]"); + } + + + /** + * Assert that an array has elements; that is, it must not be + * null and must have at least one element. + *
Assert.notEmpty(array, "The array must have elements");
+ * @param array the array to check + * @param message the exception message to use if the assertion fails + * @throws IllegalArgumentException if the object array is null or has no elements + */ + public static void notEmpty(Object[] array, String message) { + if (ObjectUtils.isEmpty(array)) { + throw new IllegalArgumentException(message); + } + } + + /** + * Assert that an array has elements; that is, it must not be + * null and must have at least one element. + *
Assert.notEmpty(array);
+ * @param array the array to check + * @throws IllegalArgumentException if the object array is null or has no elements + */ + public static void notEmpty(Object[] array) { + notEmpty(array, "[Assertion failed] - this array must not be empty: it must contain at least 1 element"); + } + + /** + * Assert that an array has no null elements. + * Note: Does not complain if the array is empty! + *
Assert.noNullElements(array, "The array must have non-null elements");
+ * @param array the array to check + * @param message the exception message to use if the assertion fails + * @throws IllegalArgumentException if the object array contains a null element + */ + public static void noNullElements(Object[] array, String message) { + if (array != null) { + for (int i = 0; i < array.length; i++) { + if (array[i] == null) { + throw new IllegalArgumentException(message); + } + } + } + } + + /** + * Assert that an array has no null elements. + * Note: Does not complain if the array is empty! + *
Assert.noNullElements(array);
+ * @param array the array to check + * @throws IllegalArgumentException if the object array contains a null element + */ + public static void noNullElements(Object[] array) { + noNullElements(array, "[Assertion failed] - this array must not contain any null elements"); + } + + /** + * Assert that a collection has elements; that is, it must not be + * null and must have at least one element. + *
Assert.notEmpty(collection, "Collection must have elements");
+ * @param collection the collection to check + * @param message the exception message to use if the assertion fails + * @throws IllegalArgumentException if the collection is null or has no elements + */ + public static void notEmpty(Collection collection, String message) { + if (CollectionUtils.isEmpty(collection)) { + throw new IllegalArgumentException(message); + } + } + + /** + * Assert that a collection has elements; that is, it must not be + * null and must have at least one element. + *
Assert.notEmpty(collection, "Collection must have elements");
+ * @param collection the collection to check + * @throws IllegalArgumentException if the collection is null or has no elements + */ + public static void notEmpty(Collection collection) { + notEmpty(collection, + "[Assertion failed] - this collection must not be empty: it must contain at least 1 element"); + } + + /** + * Assert that a Map has entries; that is, it must not be null + * and must have at least one entry. + *
Assert.notEmpty(map, "Map must have entries");
+ * @param map the map to check + * @param message the exception message to use if the assertion fails + * @throws IllegalArgumentException if the map is null or has no entries + */ + public static void notEmpty(Map map, String message) { + if (CollectionUtils.isEmpty(map)) { + throw new IllegalArgumentException(message); + } + } + + /** + * Assert that a Map has entries; that is, it must not be null + * and must have at least one entry. + *
Assert.notEmpty(map);
+ * @param map the map to check + * @throws IllegalArgumentException if the map is null or has no entries + */ + public static void notEmpty(Map map) { + notEmpty(map, "[Assertion failed] - this map must not be empty; it must contain at least one entry"); + } + + + /** + * Assert that the provided object is an instance of the provided class. + *
Assert.instanceOf(Foo.class, foo);
+ * @param clazz the required class + * @param obj the object to check + * @throws IllegalArgumentException if the object is not an instance of clazz + * @see Class#isInstance + */ + public static void isInstanceOf(Class clazz, Object obj) { + isInstanceOf(clazz, obj, ""); + } + + /** + * Assert that the provided object is an instance of the provided class. + *
Assert.instanceOf(Foo.class, foo);
+ * @param type the type to check against + * @param obj the object to check + * @param message a message which will be prepended to the message produced by + * the function itself, and which may be used to provide context. It should + * normally end in a ": " or ". " so that the function generate message looks + * ok when prepended to it. + * @throws IllegalArgumentException if the object is not an instance of clazz + * @see Class#isInstance + */ + public static void isInstanceOf(Class type, Object obj, String message) { + notNull(type, "Type to check against must not be null"); + if (!type.isInstance(obj)) { + throw new IllegalArgumentException(message + + "Object of class [" + (obj != null ? obj.getClass().getName() : "null") + + "] must be an instance of " + type); + } + } + + /** + * Assert that superType.isAssignableFrom(subType) is true. + *
Assert.isAssignable(Number.class, myClass);
+ * @param superType the super type to check + * @param subType the sub type to check + * @throws IllegalArgumentException if the classes are not assignable + */ + public static void isAssignable(Class superType, Class subType) { + isAssignable(superType, subType, ""); + } + + /** + * Assert that superType.isAssignableFrom(subType) is true. + *
Assert.isAssignable(Number.class, myClass);
+ * @param superType the super type to check against + * @param subType the sub type to check + * @param message a message which will be prepended to the message produced by + * the function itself, and which may be used to provide context. It should + * normally end in a ": " or ". " so that the function generate message looks + * ok when prepended to it. + * @throws IllegalArgumentException if the classes are not assignable + */ + public static void isAssignable(Class superType, Class subType, String message) { + notNull(superType, "Type to check against must not be null"); + if (subType == null || !superType.isAssignableFrom(subType)) { + throw new IllegalArgumentException(message + subType + " is not assignable to " + superType); + } + } + + + /** + * Assert a boolean expression, throwing IllegalStateException + * if the test result is false. Call isTrue if you wish to + * throw IllegalArgumentException on an assertion failure. + *
Assert.state(id == null, "The id property must not already be initialized");
+ * @param expression a boolean expression + * @param message the exception message to use if the assertion fails + * @throws IllegalStateException if expression is false + */ + public static void state(boolean expression, String message) { + if (!expression) { + throw new IllegalStateException(message); + } + } + + /** + * Assert a boolean expression, throwing {@link IllegalStateException} + * if the test result is false. + *

Call {@link #isTrue(boolean)} if you wish to + * throw {@link IllegalArgumentException} on an assertion failure. + *

Assert.state(id == null);
+ * @param expression a boolean expression + * @throws IllegalStateException if the supplied expression is false + */ + public static void state(boolean expression) { + state(expression, "[Assertion failed] - this state invariant must be true"); + } + +} Index: 3rdParty_sources/spring/org/springframework/util/AutoPopulatingList.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/util/AutoPopulatingList.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/util/AutoPopulatingList.java 17 Aug 2012 15:16:09 -0000 1.1 @@ -0,0 +1,274 @@ +/* + * 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.util; + +import java.io.Serializable; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import java.util.ListIterator; + +/** + * Simple {@link List} wrapper class that allows for elements to be + * automatically populated as they are requested. This is particularly + * useful for data binding to {@link List Lists}, allowing for elements + * to be created and added to the {@link List} in a "just in time" fashion. + * + *

Note: This class is not thread-safe. To create a thread-safe version, + * use the {@link java.util.Collections#synchronizedList} utility methods. + * + *

Inspired by LazyList from Commons Collections. + * + * @author Rob Harrop + * @author Juergen Hoeller + * @since 2.0 + */ +public class AutoPopulatingList implements List, Serializable { + + /** + * The {@link List} that all operations are eventually delegated to. + */ + private final List backingList; + + /** + * The {@link ElementFactory} to use to create new {@link List} elements + * on demand. + */ + private final ElementFactory elementFactory; + + + /** + * Creates a new AutoPopulatingList that is backed by a standard + * {@link ArrayList} and adds new instances of the supplied {@link Class element Class} + * to the backing {@link List} on demand. + */ + public AutoPopulatingList(Class elementClass) { + this(new ArrayList(), elementClass); + } + + /** + * Creates a new AutoPopulatingList that is backed by the supplied {@link List} + * and adds new instances of the supplied {@link Class element Class} to the backing + * {@link List} on demand. + */ + public AutoPopulatingList(List backingList, Class elementClass) { + this(backingList, new ReflectiveElementFactory(elementClass)); + } + + /** + * Creates a new AutoPopulatingList that is backed by a standard + * {@link ArrayList} and creates new elements on demand using the supplied {@link ElementFactory}. + */ + public AutoPopulatingList(ElementFactory elementFactory) { + this(new ArrayList(), elementFactory); + } + + /** + * Creates a new AutoPopulatingList that is backed by the supplied {@link List} + * and creates new elements on demand using the supplied {@link ElementFactory}. + */ + public AutoPopulatingList(List backingList, ElementFactory elementFactory) { + Assert.notNull(backingList, "Backing List must not be null"); + Assert.notNull(elementFactory, "Element factory must not be null"); + this.backingList = backingList; + this.elementFactory = elementFactory; + } + + + public void add(int index, Object element) { + this.backingList.add(index, element); + } + + public boolean add(Object o) { + return this.backingList.add(o); + } + + public boolean addAll(Collection c) { + return this.backingList.addAll(c); + } + + public boolean addAll(int index, Collection c) { + return this.backingList.addAll(index, c); + } + + public void clear() { + this.backingList.clear(); + } + + public boolean contains(Object o) { + return this.backingList.contains(o); + } + + public boolean containsAll(Collection c) { + return this.backingList.containsAll(c); + } + + public boolean equals(Object o) { + return this.backingList.equals(o); + } + + /** + * Get the element at the supplied index, creating it if there is + * no element at that index. + */ + public Object get(int index) { + int backingListSize = this.backingList.size(); + + Object element = null; + if (index < backingListSize) { + element = this.backingList.get(index); + if (element == null) { + element = this.elementFactory.createElement(index); + this.backingList.set(index, element); + } + } + else { + for (int x = backingListSize; x < index; x++) { + this.backingList.add(null); + } + element = this.elementFactory.createElement(index); + this.backingList.add(element); + } + return element; + } + + public int hashCode() { + return this.backingList.hashCode(); + } + + public int indexOf(Object o) { + return this.backingList.indexOf(o); + } + + public boolean isEmpty() { + return this.backingList.isEmpty(); + } + + public Iterator iterator() { + return this.backingList.iterator(); + } + + public int lastIndexOf(Object o) { + return this.backingList.lastIndexOf(o); + } + + public ListIterator listIterator() { + return this.backingList.listIterator(); + } + + public ListIterator listIterator(int index) { + return this.backingList.listIterator(index); + } + + public Object remove(int index) { + return this.backingList.remove(index); + } + + public boolean remove(Object o) { + return this.backingList.remove(o); + } + + public boolean removeAll(Collection c) { + return this.backingList.removeAll(c); + } + + public boolean retainAll(Collection c) { + return this.backingList.retainAll(c); + } + + public Object set(int index, Object element) { + return this.backingList.set(index, element); + } + + public int size() { + return this.backingList.size(); + } + + public List subList(int fromIndex, int toIndex) { + return this.backingList.subList(fromIndex, toIndex); + } + + public Object[] toArray() { + return this.backingList.toArray(); + } + + public Object[] toArray(Object[] a) { + return this.backingList.toArray(a); + } + + + /** + * Factory interface for creating elements for an index-based access + * data structure such as a {@link java.util.List}. + */ + public interface ElementFactory { + + /** + * Create the element for the supplied index. + * @return the element object + * @throws ElementInstantiationException if the instantiation process failed + * (any exception thrown by a target constructor should be propagated as-is) + */ + Object createElement(int index) throws ElementInstantiationException; + } + + + /** + * Exception to be thrown from ElementFactory. + */ + public static class ElementInstantiationException extends RuntimeException { + + public ElementInstantiationException(String msg) { + super(msg); + } + } + + + /** + * Reflective implementation of the ElementFactory interface, + * using Class.newInstance() on a given element class. + * @see java.lang.Class#newInstance() + */ + private static class ReflectiveElementFactory implements ElementFactory, Serializable { + + private final Class elementClass; + + public ReflectiveElementFactory(Class elementClass) { + Assert.notNull(elementClass, "Element clas must not be null"); + Assert.isTrue(!elementClass.isInterface(), "Element class must not be an interface type"); + Assert.isTrue(!Modifier.isAbstract(elementClass.getModifiers()), "Element class cannot be an abstract class"); + this.elementClass = elementClass; + } + + public Object createElement(int index) { + try { + return this.elementClass.newInstance(); + } + catch (InstantiationException ex) { + throw new ElementInstantiationException("Unable to instantiate element class [" + + this.elementClass.getName() + "]. Root cause is " + ex); + } + catch (IllegalAccessException ex) { + throw new ElementInstantiationException("Cannot access element class [" + + this.elementClass.getName() + "]. Root cause is " + ex); + } + } + } + +} Index: 3rdParty_sources/spring/org/springframework/util/CachingMapDecorator.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/util/CachingMapDecorator.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/util/CachingMapDecorator.java 17 Aug 2012 15:16:09 -0000 1.1 @@ -0,0 +1,276 @@ +/* + * 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.util; + +import java.io.Serializable; +import java.lang.ref.Reference; +import java.lang.ref.WeakReference; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedHashSet; +import java.util.LinkedList; +import java.util.Map; +import java.util.Set; +import java.util.WeakHashMap; + +/** + * A simple decorator for a Map, encapsulating the workflow for caching + * expensive values in a target Map. Supports caching weak or strong keys. + * + *

This class is also an abstract template. Caching Map implementations + * should subclass and override the create(key) method which + * encapsulates expensive creation of a new object. + * + * @author Keith Donald + * @author Juergen Hoeller + * @since 1.2.2 + */ +public class CachingMapDecorator implements Map, Serializable { + + protected static Object NULL_VALUE = new Object(); + + + private final Map targetMap; + + private final boolean synchronize; + + private final boolean weak; + + + /** + * Create a CachingMapDecorator with strong keys, + * using an underlying synchronized Map. + */ + public CachingMapDecorator() { + this(false); + } + + /** + * Create a CachingMapDecorator, + * using an underlying synchronized Map. + * @param weak whether to use weak references for keys and values + */ + public CachingMapDecorator(boolean weak) { + Map internalMap = weak ? (Map) new WeakHashMap() : new HashMap(); + this.targetMap = Collections.synchronizedMap(internalMap); + this.synchronize = true; + this.weak = weak; + } + + /** + * Create a CachingMapDecorator with initial size, + * using an underlying synchronized Map. + * @param weak whether to use weak references for keys and values + * @param size the initial cache size + */ + public CachingMapDecorator(boolean weak, int size) { + Map internalMap = weak ? (Map) new WeakHashMap(size) : new HashMap(size); + this.targetMap = Collections.synchronizedMap(internalMap); + this.synchronize = true; + this.weak = weak; + } + + /** + * Create a CachingMapDecorator for the given Map. + *

The passed-in Map won't get synchronized explicitly, + * so make sure to pass in a properly synchronized Map, if desired. + * @param targetMap the Map to decorate + */ + public CachingMapDecorator(Map targetMap) { + this(targetMap, false, false); + } + + /** + * Create a CachingMapDecorator for the given Map. + *

The passed-in Map won't get synchronized explicitly unless + * you specify "synchronize" as "true". + * @param targetMap the Map to decorate + * @param synchronize whether to synchronize on the given Map + * @param weak whether to use weak references for values + */ + public CachingMapDecorator(Map targetMap, boolean synchronize, boolean weak) { + Assert.notNull(targetMap, "Target Map is required"); + this.targetMap = (synchronize ? Collections.synchronizedMap(targetMap) : targetMap); + this.synchronize = synchronize; + this.weak = weak; + } + + + public int size() { + return this.targetMap.size(); + } + + public boolean isEmpty() { + return this.targetMap.isEmpty(); + } + + public boolean containsKey(Object key) { + return this.targetMap.containsKey(key); + } + + public boolean containsValue(Object value) { + Object valueToCheck = value; + if (valueToCheck == null) { + valueToCheck = NULL_VALUE; + } + if (this.synchronize) { + synchronized (this.targetMap) { + return containsValueOrReference(valueToCheck); + } + } + else { + return containsValueOrReference(valueToCheck); + } + } + + private boolean containsValueOrReference(Object value) { + if (this.targetMap.containsValue(value)) { + return true; + } + for (Iterator it = this.targetMap.values().iterator(); it.hasNext();) { + Object mapVal = it.next(); + if (mapVal instanceof Reference && value.equals(((Reference) mapVal).get())) { + return true; + } + } + return false; + } + + public Object remove(Object key) { + return this.targetMap.remove(key); + } + + public void putAll(Map map) { + this.targetMap.putAll(map); + } + + public void clear() { + this.targetMap.clear(); + } + + public Set keySet() { + if (this.synchronize) { + synchronized (this.targetMap) { + return new LinkedHashSet(this.targetMap.keySet()); + } + } + else { + return new LinkedHashSet(this.targetMap.keySet()); + } + } + + public Collection values() { + if (this.synchronize) { + synchronized (this.targetMap) { + return valuesCopy(); + } + } + else { + return valuesCopy(); + } + } + + private Collection valuesCopy() { + LinkedList values = new LinkedList(); + for (Iterator it = this.targetMap.values().iterator(); it.hasNext();) { + Object value = it.next(); + values.add(value instanceof Reference ? ((Reference) value).get() : value); + } + return values; + } + + public Set entrySet() { + if (this.synchronize) { + synchronized (this.targetMap) { + return new LinkedHashSet(this.targetMap.entrySet()); + } + } + else { + return new LinkedHashSet(this.targetMap.entrySet()); + } + } + + + /** + * Put an object into the cache, possibly wrapping it with a weak + * reference. + * @see #useWeakValue(Object, Object) + */ + public Object put(Object key, Object value) { + Object newValue = value; + if (newValue == null) { + newValue = NULL_VALUE; + } + if (useWeakValue(key, newValue)) { + newValue = new WeakReference(newValue); + } + return this.targetMap.put(key, newValue); + } + + /** + * Decide whether use a weak reference for the value of + * the given key-value pair. + * @param key the candidate key + * @param value the candidate value + * @return true in order to use a weak reference; + * false otherwise. + */ + protected boolean useWeakValue(Object key, Object value) { + return this.weak; + } + + /** + * Get value for key. + * Creates and caches value if it doesn't already exist in the cache. + *

This implementation is not synchronized: This is highly + * concurrent but does not guarantee unique instances in the cache, + * as multiple values for the same key could get created in parallel. + * Consider overriding this method to synchronize it, if desired. + * @see #create(Object) + */ + public Object get(Object key) { + Object value = this.targetMap.get(key); + if (value instanceof Reference) { + value = ((Reference) value).get(); + } + if (value == null) { + value = create(key); + if (value != null) { + put(key, value); + } + } + return (value == NULL_VALUE ? null : value); + } + + /** + * Create a value to cache for the given key. + * Called by get if there is no value cached already. + * @param key the cache key + * @see #get(Object) + */ + protected Object create(Object key) { + return null; + } + + + public String toString() { + return "CachingMapDecorator [" + getClass().getName() + "]:" + this.targetMap; + } + +} Index: 3rdParty_sources/spring/org/springframework/util/ClassLoaderUtils.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/util/ClassLoaderUtils.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/util/ClassLoaderUtils.java 17 Aug 2012 15:16:09 -0000 1.1 @@ -0,0 +1,100 @@ +/* + * 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.util; + +/** + * Utility class for diagnostic purposes, to analyze the + * ClassLoader hierarchy for any given object or class loader. + * + * @author Rod Johnson + * @author Juergen Hoeller + * @since 02 April 2001 + * @deprecated as of Spring 2.5, to be removed in Spring 3.0 + * @see java.lang.ClassLoader + */ +public abstract class ClassLoaderUtils { + + /** + * Show the class loader hierarchy for this class. + * Uses default line break and tab text characters. + * @param obj object to analyze loader hierarchy for + * @param role a description of the role of this class in the application + * (e.g., "servlet" or "EJB reference") + * @return a String showing the class loader hierarchy for this class + */ + public static String showClassLoaderHierarchy(Object obj, String role) { + return showClassLoaderHierarchy(obj, role, "\n", "\t"); + } + + /** + * Show the class loader hierarchy for this class. + * @param obj object to analyze loader hierarchy for + * @param role a description of the role of this class in the application + * (e.g., "servlet" or "EJB reference") + * @param lineBreak line break + * @param tabText text to use to set tabs + * @return a String showing the class loader hierarchy for this class + */ + public static String showClassLoaderHierarchy(Object obj, String role, String lineBreak, String tabText) { + String s = "object of " + obj.getClass() + ": role is " + role + lineBreak; + return s + showClassLoaderHierarchy(obj.getClass().getClassLoader(), lineBreak, tabText, 0); + } + + /** + * Show the class loader hierarchy for the given class loader. + * Uses default line break and tab text characters. + * @param cl class loader to analyze hierarchy for + * @return a String showing the class loader hierarchy for this class + */ + public static String showClassLoaderHierarchy(ClassLoader cl) { + return showClassLoaderHierarchy(cl, "\n", "\t"); + } + + /** + * Show the class loader hierarchy for the given class loader. + * @param cl class loader to analyze hierarchy for + * @param lineBreak line break + * @param tabText text to use to set tabs + * @return a String showing the class loader hierarchy for this class + */ + public static String showClassLoaderHierarchy(ClassLoader cl, String lineBreak, String tabText) { + return showClassLoaderHierarchy(cl, lineBreak, tabText, 0); + } + + /** + * Show the class loader hierarchy for the given class loader. + * @param cl class loader to analyze hierarchy for + * @param lineBreak line break + * @param tabText text to use to set tabs + * @param indent nesting level (from 0) of this loader; used in pretty printing + * @return a String showing the class loader hierarchy for this class + */ + private static String showClassLoaderHierarchy(ClassLoader cl, String lineBreak, String tabText, int indent) { + if (cl == null) { + ClassLoader ccl = Thread.currentThread().getContextClassLoader(); + return "context class loader=[" + ccl + "] hashCode=" + ccl.hashCode(); + } + StringBuffer buf = new StringBuffer(); + for (int i = 0; i < indent; i++) { + buf.append(tabText); + } + buf.append("[").append(cl).append("] hashCode=").append(cl.hashCode()).append(lineBreak); + ClassLoader parent = cl.getParent(); + return buf.toString() + showClassLoaderHierarchy(parent, lineBreak, tabText, indent + 1); + } + +} Index: 3rdParty_sources/spring/org/springframework/util/ClassUtils.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/util/ClassUtils.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/util/ClassUtils.java 17 Aug 2012 15:16:10 -0000 1.1 @@ -0,0 +1,982 @@ +/* + * 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.util; + +import java.beans.Introspector; +import java.lang.reflect.Array; +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.lang.reflect.Proxy; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * Miscellaneous class utility methods. Mainly for internal use within the + * framework; consider Jakarta's Commons Lang for a more comprehensive suite + * of class utilities. + * + * @author Keith Donald + * @author Rob Harrop + * @author Juergen Hoeller + * @since 1.1 + * @see TypeUtils + * @see ReflectionUtils + */ +public abstract class ClassUtils { + + /** Suffix for array class names: "[]" */ + public static final String ARRAY_SUFFIX = "[]"; + + /** Prefix for internal array class names: "[L" */ + private static final String INTERNAL_ARRAY_PREFIX = "[L"; + + /** The package separator character '.' */ + private static final char PACKAGE_SEPARATOR = '.'; + + /** The inner class separator character '$' */ + private static final char INNER_CLASS_SEPARATOR = '$'; + + /** The CGLIB class separator character "$$" */ + public static final String CGLIB_CLASS_SEPARATOR = "$$"; + + /** The ".class" file suffix */ + public static final String CLASS_FILE_SUFFIX = ".class"; + + + /** + * Map with primitive wrapper type as key and corresponding primitive + * type as value, for example: Integer.class -> int.class. + */ + private static final Map primitiveWrapperTypeMap = new HashMap(8); + + /** + * Map with primitive type name as key and corresponding primitive + * type as value, for example: "int" -> "int.class". + */ + private static final Map primitiveTypeNameMap = new HashMap(16); + + + static { + primitiveWrapperTypeMap.put(Boolean.class, boolean.class); + primitiveWrapperTypeMap.put(Byte.class, byte.class); + primitiveWrapperTypeMap.put(Character.class, char.class); + primitiveWrapperTypeMap.put(Double.class, double.class); + primitiveWrapperTypeMap.put(Float.class, float.class); + primitiveWrapperTypeMap.put(Integer.class, int.class); + primitiveWrapperTypeMap.put(Long.class, long.class); + primitiveWrapperTypeMap.put(Short.class, short.class); + + Set primitiveTypeNames = new HashSet(16); + primitiveTypeNames.addAll(primitiveWrapperTypeMap.values()); + primitiveTypeNames.addAll(Arrays.asList(new Class[] { + boolean[].class, byte[].class, char[].class, double[].class, + float[].class, int[].class, long[].class, short[].class})); + for (Iterator it = primitiveTypeNames.iterator(); it.hasNext();) { + Class primitiveClass = (Class) it.next(); + primitiveTypeNameMap.put(primitiveClass.getName(), primitiveClass); + } + } + + + /** + * Return the default ClassLoader to use: typically the thread context + * ClassLoader, if available; the ClassLoader that loaded the ClassUtils + * class will be used as fallback. + *

Call this method if you intend to use the thread context ClassLoader + * in a scenario where you absolutely need a non-null ClassLoader reference: + * for example, for class path resource loading (but not necessarily for + * Class.forName, which accepts a null ClassLoader + * reference as well). + * @return the default ClassLoader (never null) + * @see java.lang.Thread#getContextClassLoader() + */ + public static ClassLoader getDefaultClassLoader() { + ClassLoader cl = null; + try { + cl = Thread.currentThread().getContextClassLoader(); + } + catch (Throwable ex) { + // Cannot access thread context ClassLoader - falling back to system class loader... + } + if (cl == null) { + // No thread context class loader -> use class loader of this class. + cl = ClassUtils.class.getClassLoader(); + } + return cl; + } + + /** + * Override the thread context ClassLoader with the environment's bean ClassLoader + * if necessary, i.e. if the bean ClassLoader is not equivalent to the thread + * context ClassLoader already. + * @param classLoaderToUse the actual ClassLoader to use for the thread context + * @return the original thread context ClassLoader, or null if not overridden + */ + public static ClassLoader overrideThreadContextClassLoader(ClassLoader classLoaderToUse) { + Thread currentThread = Thread.currentThread(); + ClassLoader threadContextClassLoader = currentThread.getContextClassLoader(); + if (classLoaderToUse != null && !classLoaderToUse.equals(threadContextClassLoader)) { + currentThread.setContextClassLoader(classLoaderToUse); + return threadContextClassLoader; + } + else { + return null; + } + } + + /** + * Replacement for Class.forName() that also returns Class instances + * for primitives (like "int") and array class names (like "String[]"). + *

Always uses the default class loader: that is, preferably the thread context + * class loader, or the ClassLoader that loaded the ClassUtils class as fallback. + * @param name the name of the Class + * @return Class instance for the supplied name + * @throws ClassNotFoundException if the class was not found + * @throws LinkageError if the class file could not be loaded + * @see Class#forName(String, boolean, ClassLoader) + * @see #getDefaultClassLoader() + */ + public static Class forName(String name) throws ClassNotFoundException, LinkageError { + return forName(name, getDefaultClassLoader()); + } + + /** + * Replacement for Class.forName() that also returns Class instances + * for primitives (like "int") and array class names (like "String[]"). + * @param name the name of the Class + * @param classLoader the class loader to use + * (may be null, which indicates the default class loader) + * @return Class instance for the supplied name + * @throws ClassNotFoundException if the class was not found + * @throws LinkageError if the class file could not be loaded + * @see Class#forName(String, boolean, ClassLoader) + */ + public static Class forName(String name, ClassLoader classLoader) throws ClassNotFoundException, LinkageError { + Assert.notNull(name, "Name must not be null"); + + Class clazz = resolvePrimitiveClassName(name); + if (clazz != null) { + return clazz; + } + + // "java.lang.String[]" style arrays + if (name.endsWith(ARRAY_SUFFIX)) { + String elementClassName = name.substring(0, name.length() - ARRAY_SUFFIX.length()); + Class elementClass = forName(elementClassName, classLoader); + return Array.newInstance(elementClass, 0).getClass(); + } + + // "[Ljava.lang.String;" style arrays + int internalArrayMarker = name.indexOf(INTERNAL_ARRAY_PREFIX); + if (internalArrayMarker != -1 && name.endsWith(";")) { + String elementClassName = null; + if (internalArrayMarker == 0) { + elementClassName = name.substring(INTERNAL_ARRAY_PREFIX.length(), name.length() - 1); + } + else if (name.startsWith("[")) { + elementClassName = name.substring(1); + } + Class elementClass = forName(elementClassName, classLoader); + return Array.newInstance(elementClass, 0).getClass(); + } + + ClassLoader classLoaderToUse = classLoader; + if (classLoaderToUse == null) { + classLoaderToUse = getDefaultClassLoader(); + } + return classLoaderToUse.loadClass(name); + } + + /** + * Resolve the given class name into a Class instance. Supports + * primitives (like "int") and array class names (like "String[]"). + *

This is effectively equivalent to the forName + * method with the same arguments, with the only difference being + * the exceptions thrown in case of class loading failure. + * @param className the name of the Class + * @param classLoader the class loader to use + * (may be null, which indicates the default class loader) + * @return Class instance for the supplied name + * @throws IllegalArgumentException if the class name was not resolvable + * (that is, the class could not be found or the class file could not be loaded) + * @see #forName(String, ClassLoader) + */ + public static Class resolveClassName(String className, ClassLoader classLoader) throws IllegalArgumentException { + try { + return forName(className, classLoader); + } + catch (ClassNotFoundException ex) { + IllegalArgumentException iae = new IllegalArgumentException("Cannot find class [" + className + "]"); + iae.initCause(ex); + throw iae; + } + catch (LinkageError ex) { + IllegalArgumentException iae = new IllegalArgumentException( + "Error loading class [" + className + "]: problem with class file or dependent class."); + iae.initCause(ex); + throw iae; + } + } + + /** + * Resolve the given class name as primitive class, if appropriate, + * according to the JVM's naming rules for primitive classes. + *

Also supports the JVM's internal class names for primitive arrays. + * Does not support the "[]" suffix notation for primitive arrays; + * this is only supported by {@link #forName}. + * @param name the name of the potentially primitive class + * @return the primitive class, or null if the name does not denote + * a primitive class or primitive array class + */ + public static Class resolvePrimitiveClassName(String name) { + Class result = null; + // Most class names will be quite long, considering that they + // SHOULD sit in a package, so a length check is worthwhile. + if (name != null && name.length() <= 8) { + // Could be a primitive - likely. + result = (Class) primitiveTypeNameMap.get(name); + } + return result; + } + + /** + * Determine whether the {@link Class} identified by the supplied name is present + * and can be loaded. Will return false if either the class or + * one of its dependencies is not present or cannot be loaded. + * @param className the name of the class to check + * @return whether the specified class is present + * @deprecated as of Spring 2.5, in favor of {@link #isPresent(String, ClassLoader)} + */ + public static boolean isPresent(String className) { + return isPresent(className, getDefaultClassLoader()); + } + + /** + * Determine whether the {@link Class} identified by the supplied name is present + * and can be loaded. Will return false if either the class or + * one of its dependencies is not present or cannot be loaded. + * @param className the name of the class to check + * @param classLoader the class loader to use + * (may be null, which indicates the default class loader) + * @return whether the specified class is present + */ + public static boolean isPresent(String className, ClassLoader classLoader) { + try { + forName(className, classLoader); + return true; + } + catch (Throwable ex) { + // Class or one of its dependencies is not present... + return false; + } + } + + /** + * Return the user-defined class for the given instance: usually simply + * the class of the given instance, but the original class in case of a + * CGLIB-generated subclass. + * @param instance the instance to check + * @return the user-defined class + */ + public static Class getUserClass(Object instance) { + Assert.notNull(instance, "Instance must not be null"); + return getUserClass(instance.getClass()); + } + + /** + * Return the user-defined class for the given class: usually simply the given + * class, but the original class in case of a CGLIB-generated subclass. + * @param clazz the class to check + * @return the user-defined class + */ + public static Class getUserClass(Class clazz) { + return (clazz != null && clazz.getName().indexOf(CGLIB_CLASS_SEPARATOR) != -1 ? + clazz.getSuperclass() : clazz); + } + + /** + * Check whether the given class is cache-safe in the given context, + * i.e. whether it is loaded by the given ClassLoader or a parent of it. + * @param clazz the class to analyze + * @param classLoader the ClassLoader to potentially cache metadata in + */ + public static boolean isCacheSafe(Class clazz, ClassLoader classLoader) { + Assert.notNull(clazz, "Class must not be null"); + ClassLoader target = clazz.getClassLoader(); + if (target == null) { + return false; + } + ClassLoader cur = classLoader; + if (cur == target) { + return true; + } + while (cur != null) { + cur = cur.getParent(); + if (cur == target) { + return true; + } + } + return false; + } + + + /** + * Get the class name without the qualified package name. + * @param className the className to get the short name for + * @return the class name of the class without the package name + * @throws IllegalArgumentException if the className is empty + */ + public static String getShortName(String className) { + Assert.hasLength(className, "Class name must not be empty"); + int lastDotIndex = className.lastIndexOf(PACKAGE_SEPARATOR); + int nameEndIndex = className.indexOf(CGLIB_CLASS_SEPARATOR); + if (nameEndIndex == -1) { + nameEndIndex = className.length(); + } + String shortName = className.substring(lastDotIndex + 1, nameEndIndex); + shortName = shortName.replace(INNER_CLASS_SEPARATOR, PACKAGE_SEPARATOR); + return shortName; + } + + /** + * Get the class name without the qualified package name. + * @param clazz the class to get the short name for + * @return the class name of the class without the package name + */ + public static String getShortName(Class clazz) { + return getShortName(getQualifiedName(clazz)); + } + + /** + * Return the short string name of a Java class in decapitalized JavaBeans + * property format. Strips the outer class name in case of an inner class. + * @param clazz the class + * @return the short name rendered in a standard JavaBeans property format + * @see java.beans.Introspector#decapitalize(String) + */ + public static String getShortNameAsProperty(Class clazz) { + String shortName = ClassUtils.getShortName(clazz); + int dotIndex = shortName.lastIndexOf('.'); + shortName = (dotIndex != -1 ? shortName.substring(dotIndex + 1) : shortName); + return Introspector.decapitalize(shortName); + } + + /** + * Determine the name of the class file, relative to the containing + * package: e.g. "String.class" + * @param clazz the class + * @return the file name of the ".class" file + */ + public static String getClassFileName(Class clazz) { + Assert.notNull(clazz, "Class must not be null"); + String className = clazz.getName(); + int lastDotIndex = className.lastIndexOf(PACKAGE_SEPARATOR); + return className.substring(lastDotIndex + 1) + CLASS_FILE_SUFFIX; + } + + /** + * Determine the name of the package of the given class: + * e.g. "java.lang" for the java.lang.String class. + * @param clazz the class + * @return the package name, or the empty String if the class + * is defined in the default package + */ + public static String getPackageName(Class clazz) { + Assert.notNull(clazz, "Class must not be null"); + String className = clazz.getName(); + int lastDotIndex = className.lastIndexOf(PACKAGE_SEPARATOR); + return (lastDotIndex != -1 ? className.substring(0, lastDotIndex) : ""); + } + + /** + * Return the qualified name of the given class: usually simply + * the class name, but component type class name + "[]" for arrays. + * @param clazz the class + * @return the qualified name of the class + */ + public static String getQualifiedName(Class clazz) { + Assert.notNull(clazz, "Class must not be null"); + if (clazz.isArray()) { + return getQualifiedNameForArray(clazz); + } + else { + return clazz.getName(); + } + } + + /** + * Build a nice qualified name for an array: + * component type class name + "[]". + * @param clazz the array class + * @return a qualified name for the array class + */ + private static String getQualifiedNameForArray(Class clazz) { + StringBuffer buffer = new StringBuffer(); + while (clazz.isArray()) { + clazz = clazz.getComponentType(); + buffer.append(ClassUtils.ARRAY_SUFFIX); + } + buffer.insert(0, clazz.getName()); + return buffer.toString(); + } + + /** + * Return the qualified name of the given method, consisting of + * fully qualified interface/class name + "." + method name. + * @param method the method + * @return the qualified name of the method + */ + public static String getQualifiedMethodName(Method method) { + Assert.notNull(method, "Method must not be null"); + return method.getDeclaringClass().getName() + "." + method.getName(); + } + + /** + * Return a descriptive name for the given object's type: usually simply + * the class name, but component type class name + "[]" for arrays, + * and an appended list of implemented interfaces for JDK proxies. + * @param value the value to introspect + * @return the qualified name of the class + */ + public static String getDescriptiveType(Object value) { + if (value == null) { + return null; + } + Class clazz = value.getClass(); + if (Proxy.isProxyClass(clazz)) { + StringBuffer buf = new StringBuffer(clazz.getName()); + buf.append(" implementing "); + Class[] ifcs = clazz.getInterfaces(); + for (int i = 0; i < ifcs.length; i++) { + buf.append(ifcs[i].getName()); + if (i < ifcs.length - 1) { + buf.append(','); + } + } + return buf.toString(); + } + else if (clazz.isArray()) { + return getQualifiedNameForArray(clazz); + } + else { + return clazz.getName(); + } + } + + + /** + * Determine whether the given class has a constructor with the given signature. + *

Essentially translates NoSuchMethodException to "false". + * @param clazz the clazz to analyze + * @param paramTypes the parameter types of the method + * @return whether the class has a corresponding constructor + * @see java.lang.Class#getMethod + */ + public static boolean hasConstructor(Class clazz, Class[] paramTypes) { + return (getConstructorIfAvailable(clazz, paramTypes) != null); + } + + /** + * Determine whether the given class has a constructor with the given signature, + * and return it if available (else return null). + *

Essentially translates NoSuchMethodException to null. + * @param clazz the clazz to analyze + * @param paramTypes the parameter types of the method + * @return the constructor, or null if not found + * @see java.lang.Class#getConstructor + */ + public static Constructor getConstructorIfAvailable(Class clazz, Class[] paramTypes) { + Assert.notNull(clazz, "Class must not be null"); + try { + return clazz.getConstructor(paramTypes); + } + catch (NoSuchMethodException ex) { + return null; + } + } + + /** + * Determine whether the given class has a method with the given signature. + *

Essentially translates NoSuchMethodException to "false". + * @param clazz the clazz to analyze + * @param methodName the name of the method + * @param paramTypes the parameter types of the method + * @return whether the class has a corresponding method + * @see java.lang.Class#getMethod + */ + public static boolean hasMethod(Class clazz, String methodName, Class[] paramTypes) { + return (getMethodIfAvailable(clazz, methodName, paramTypes) != null); + } + + /** + * Determine whether the given class has a method with the given signature, + * and return it if available (else return null). + *

Essentially translates NoSuchMethodException to null. + * @param clazz the clazz to analyze + * @param methodName the name of the method + * @param paramTypes the parameter types of the method + * @return the method, or null if not found + * @see java.lang.Class#getMethod + */ + public static Method getMethodIfAvailable(Class clazz, String methodName, Class[] paramTypes) { + Assert.notNull(clazz, "Class must not be null"); + Assert.notNull(methodName, "Method name must not be null"); + try { + return clazz.getMethod(methodName, paramTypes); + } + catch (NoSuchMethodException ex) { + return null; + } + } + + /** + * Return the number of methods with a given name (with any argument types), + * for the given class and/or its superclasses. Includes non-public methods. + * @param clazz the clazz to check + * @param methodName the name of the method + * @return the number of methods with the given name + */ + public static int getMethodCountForName(Class clazz, String methodName) { + Assert.notNull(clazz, "Class must not be null"); + Assert.notNull(methodName, "Method name must not be null"); + int count = 0; + Method[] declaredMethods = clazz.getDeclaredMethods(); + for (int i = 0; i < declaredMethods.length; i++) { + Method method = declaredMethods[i]; + if (methodName.equals(method.getName())) { + count++; + } + } + Class[] ifcs = clazz.getInterfaces(); + for (int i = 0; i < ifcs.length; i++) { + count += getMethodCountForName(ifcs[i], methodName); + } + if (clazz.getSuperclass() != null) { + count += getMethodCountForName(clazz.getSuperclass(), methodName); + } + return count; + } + + /** + * Does the given class and/or its superclasses at least have one or more + * methods (with any argument types)? Includes non-public methods. + * @param clazz the clazz to check + * @param methodName the name of the method + * @return whether there is at least one method with the given name + */ + public static boolean hasAtLeastOneMethodWithName(Class clazz, String methodName) { + Assert.notNull(clazz, "Class must not be null"); + Assert.notNull(methodName, "Method name must not be null"); + Method[] declaredMethods = clazz.getDeclaredMethods(); + for (int i = 0; i < declaredMethods.length; i++) { + Method method = declaredMethods[i]; + if (method.getName().equals(methodName)) { + return true; + } + } + Class[] ifcs = clazz.getInterfaces(); + for (int i = 0; i < ifcs.length; i++) { + if (hasAtLeastOneMethodWithName(ifcs[i], methodName)) { + return true; + } + } + return (clazz.getSuperclass() != null && hasAtLeastOneMethodWithName(clazz.getSuperclass(), methodName)); + } + + /** + * Given a method, which may come from an interface, and a target class used + * in the current reflective invocation, find the corresponding target method + * if there is one. E.g. the method may be IFoo.bar() and the + * target class may be DefaultFoo. In this case, the method may be + * DefaultFoo.bar(). This enables attributes on that method to be found. + *

NOTE: In contrast to {@link org.springframework.aop.support.AopUtils#getMostSpecificMethod}, + * this method does not resolve Java 5 bridge methods automatically. + * Call {@link org.springframework.core.BridgeMethodResolver#findBridgedMethod} + * if bridge method resolution is desirable (e.g. for obtaining metadata from + * the original method definition). + * @param method the method to be invoked, which may come from an interface + * @param targetClass the target class for the current invocation. + * May be null or may not even implement the method. + * @return the specific target method, or the original method if the + * targetClass doesn't implement it or is null + * @see org.springframework.aop.support.AopUtils#getMostSpecificMethod + */ + public static Method getMostSpecificMethod(Method method, Class targetClass) { + if (method != null && targetClass != null && !targetClass.equals(method.getDeclaringClass())) { + try { + method = targetClass.getMethod(method.getName(), method.getParameterTypes()); + } + catch (NoSuchMethodException ex) { + // Perhaps the target class doesn't implement this method: + // that's fine, just use the original method. + } + } + return method; + } + + /** + * Return a static method of a class. + * @param methodName the static method name + * @param clazz the class which defines the method + * @param args the parameter types to the method + * @return the static method, or null if no static method was found + * @throws IllegalArgumentException if the method name is blank or the clazz is null + */ + public static Method getStaticMethod(Class clazz, String methodName, Class[] args) { + Assert.notNull(clazz, "Class must not be null"); + Assert.notNull(methodName, "Method name must not be null"); + try { + Method method = clazz.getDeclaredMethod(methodName, args); + if ((method.getModifiers() & Modifier.STATIC) != 0) { + return method; + } + } + catch (NoSuchMethodException ex) { + } + return null; + } + + + /** + * Check if the given class represents a primitive wrapper, + * i.e. Boolean, Byte, Character, Short, Integer, Long, Float, or Double. + * @param clazz the class to check + * @return whether the given class is a primitive wrapper class + */ + public static boolean isPrimitiveWrapper(Class clazz) { + Assert.notNull(clazz, "Class must not be null"); + return primitiveWrapperTypeMap.containsKey(clazz); + } + + /** + * Check if the given class represents a primitive (i.e. boolean, byte, + * char, short, int, long, float, or double) or a primitive wrapper + * (i.e. Boolean, Byte, Character, Short, Integer, Long, Float, or Double). + * @param clazz the class to check + * @return whether the given class is a primitive or primitive wrapper class + */ + public static boolean isPrimitiveOrWrapper(Class clazz) { + Assert.notNull(clazz, "Class must not be null"); + return (clazz.isPrimitive() || isPrimitiveWrapper(clazz)); + } + + /** + * Check if the given class represents an array of primitives, + * i.e. boolean, byte, char, short, int, long, float, or double. + * @param clazz the class to check + * @return whether the given class is a primitive array class + */ + public static boolean isPrimitiveArray(Class clazz) { + Assert.notNull(clazz, "Class must not be null"); + return (clazz.isArray() && clazz.getComponentType().isPrimitive()); + } + + /** + * Check if the given class represents an array of primitive wrappers, + * i.e. Boolean, Byte, Character, Short, Integer, Long, Float, or Double. + * @param clazz the class to check + * @return whether the given class is a primitive wrapper array class + */ + public static boolean isPrimitiveWrapperArray(Class clazz) { + Assert.notNull(clazz, "Class must not be null"); + return (clazz.isArray() && isPrimitiveWrapper(clazz.getComponentType())); + } + + /** + * Check if the right-hand side type may be assigned to the left-hand side + * type, assuming setting by reflection. Considers primitive wrapper + * classes as assignable to the corresponding primitive types. + * @param lhsType the target type + * @param rhsType the value type that should be assigned to the target type + * @return if the target type is assignable from the value type + * @see TypeUtils#isAssignable + */ + public static boolean isAssignable(Class lhsType, Class rhsType) { + Assert.notNull(lhsType, "Left-hand side type must not be null"); + Assert.notNull(rhsType, "Right-hand side type must not be null"); + return (lhsType.isAssignableFrom(rhsType) || + lhsType.equals(primitiveWrapperTypeMap.get(rhsType))); + } + + /** + * Determine if the given type is assignable from the given value, + * assuming setting by reflection. Considers primitive wrapper classes + * as assignable to the corresponding primitive types. + * @param type the target type + * @param value the value that should be assigned to the type + * @return if the type is assignable from the value + */ + public static boolean isAssignableValue(Class type, Object value) { + Assert.notNull(type, "Type must not be null"); + return (value != null ? isAssignable(type, value.getClass()) : !type.isPrimitive()); + } + + + /** + * Convert a "/"-based resource path to a "."-based fully qualified class name. + * @param resourcePath the resource path pointing to a class + * @return the corresponding fully qualified class name + */ + public static String convertResourcePathToClassName(String resourcePath) { + return resourcePath.replace('/', '.'); + } + + /** + * Convert a "."-based fully qualified class name to a "/"-based resource path. + * @param className the fully qualified class name + * @return the corresponding resource path, pointing to the class + */ + public static String convertClassNameToResourcePath(String className) { + return className.replace('.', '/'); + } + + /** + * Return a path suitable for use with ClassLoader.getResource + * (also suitable for use with Class.getResource by prepending a + * slash ('/') to the return value. Built by taking the package of the specified + * class file, converting all dots ('.') to slashes ('/'), adding a trailing slash + * if necesssary, and concatenating the specified resource name to this. + *
As such, this function may be used to build a path suitable for + * loading a resource file that is in the same package as a class file, + * although {@link org.springframework.core.io.ClassPathResource} is usually + * even more convenient. + * @param clazz the Class whose package will be used as the base + * @param resourceName the resource name to append. A leading slash is optional. + * @return the built-up resource path + * @see java.lang.ClassLoader#getResource + * @see java.lang.Class#getResource + */ + public static String addResourcePathToPackagePath(Class clazz, String resourceName) { + Assert.notNull(resourceName, "Resource name must not be null"); + if (!resourceName.startsWith("/")) { + return classPackageAsResourcePath(clazz) + "/" + resourceName; + } + return classPackageAsResourcePath(clazz) + resourceName; + } + + /** + * Given an input class object, return a string which consists of the + * class's package name as a pathname, i.e., all dots ('.') are replaced by + * slashes ('/'). Neither a leading nor trailing slash is added. The result + * could be concatenated with a slash and the name of a resource, and fed + * directly to ClassLoader.getResource(). For it to be fed to + * Class.getResource instead, a leading slash would also have + * to be prepended to the returned value. + * @param clazz the input class. A null value or the default + * (empty) package will result in an empty string ("") being returned. + * @return a path which represents the package name + * @see ClassLoader#getResource + * @see Class#getResource + */ + public static String classPackageAsResourcePath(Class clazz) { + if (clazz == null) { + return ""; + } + String className = clazz.getName(); + int packageEndIndex = className.lastIndexOf('.'); + if (packageEndIndex == -1) { + return ""; + } + String packageName = className.substring(0, packageEndIndex); + return packageName.replace('.', '/'); + } + + /** + * Build a String that consists of the names of the classes/interfaces + * in the given array. + *

Basically like AbstractCollection.toString(), but stripping + * the "class "/"interface " prefix before every class name. + * @param classes a Collection of Class objects (may be null) + * @return a String of form "[com.foo.Bar, com.foo.Baz]" + * @see java.util.AbstractCollection#toString() + */ + public static String classNamesToString(Class[] classes) { + return classNamesToString(Arrays.asList(classes)); + } + + /** + * Build a String that consists of the names of the classes/interfaces + * in the given collection. + *

Basically like AbstractCollection.toString(), but stripping + * the "class "/"interface " prefix before every class name. + * @param classes a Collection of Class objects (may be null) + * @return a String of form "[com.foo.Bar, com.foo.Baz]" + * @see java.util.AbstractCollection#toString() + */ + public static String classNamesToString(Collection classes) { + if (CollectionUtils.isEmpty(classes)) { + return "[]"; + } + StringBuffer sb = new StringBuffer("["); + for (Iterator it = classes.iterator(); it.hasNext(); ) { + Class clazz = (Class) it.next(); + sb.append(clazz.getName()); + if (it.hasNext()) { + sb.append(", "); + } + } + sb.append("]"); + return sb.toString(); + } + + + /** + * Return all interfaces that the given instance implements as array, + * including ones implemented by superclasses. + * @param instance the instance to analyse for interfaces + * @return all interfaces that the given instance implements as array + */ + public static Class[] getAllInterfaces(Object instance) { + Assert.notNull(instance, "Instance must not be null"); + return getAllInterfacesForClass(instance.getClass()); + } + + /** + * Return all interfaces that the given class implements as array, + * including ones implemented by superclasses. + *

If the class itself is an interface, it gets returned as sole interface. + * @param clazz the class to analyse for interfaces + * @return all interfaces that the given object implements as array + */ + public static Class[] getAllInterfacesForClass(Class clazz) { + return getAllInterfacesForClass(clazz, null); + } + + /** + * Return all interfaces that the given class implements as array, + * including ones implemented by superclasses. + *

If the class itself is an interface, it gets returned as sole interface. + * @param clazz the class to analyse for interfaces + * @param classLoader the ClassLoader that the interfaces need to be visible in + * (may be null when accepting all declared interfaces) + * @return all interfaces that the given object implements as array + */ + public static Class[] getAllInterfacesForClass(Class clazz, ClassLoader classLoader) { + Assert.notNull(clazz, "Class must not be null"); + if (clazz.isInterface()) { + return new Class[] {clazz}; + } + List interfaces = new ArrayList(); + while (clazz != null) { + for (int i = 0; i < clazz.getInterfaces().length; i++) { + Class ifc = clazz.getInterfaces()[i]; + if (!interfaces.contains(ifc) && + (classLoader == null || isVisible(ifc, classLoader))) { + interfaces.add(ifc); + } + } + clazz = clazz.getSuperclass(); + } + return (Class[]) interfaces.toArray(new Class[interfaces.size()]); + } + + /** + * Return all interfaces that the given instance implements as Set, + * including ones implemented by superclasses. + * @param instance the instance to analyse for interfaces + * @return all interfaces that the given instance implements as Set + */ + public static Set getAllInterfacesAsSet(Object instance) { + Assert.notNull(instance, "Instance must not be null"); + return getAllInterfacesForClassAsSet(instance.getClass()); + } + + /** + * Return all interfaces that the given class implements as Set, + * including ones implemented by superclasses. + *

If the class itself is an interface, it gets returned as sole interface. + * @param clazz the class to analyse for interfaces + * @return all interfaces that the given object implements as Set + */ + public static Set getAllInterfacesForClassAsSet(Class clazz) { + return getAllInterfacesForClassAsSet(clazz, null); + } + + /** + * Return all interfaces that the given class implements as Set, + * including ones implemented by superclasses. + *

If the class itself is an interface, it gets returned as sole interface. + * @param clazz the class to analyse for interfaces + * @param classLoader the ClassLoader that the interfaces need to be visible in + * (may be null when accepting all declared interfaces) + * @return all interfaces that the given object implements as Set + */ + public static Set getAllInterfacesForClassAsSet(Class clazz, ClassLoader classLoader) { + Assert.notNull(clazz, "Class must not be null"); + if (clazz.isInterface()) { + return Collections.singleton(clazz); + } + Set interfaces = new LinkedHashSet(); + while (clazz != null) { + for (int i = 0; i < clazz.getInterfaces().length; i++) { + Class ifc = clazz.getInterfaces()[i]; + if (classLoader == null || isVisible(ifc, classLoader)) { + interfaces.add(ifc); + } + } + clazz = clazz.getSuperclass(); + } + return interfaces; + } + + /** + * Create a composite interface Class for the given interfaces, + * implementing the given interfaces in one single Class. + *

This implementation builds a JDK proxy class for the given interfaces. + * @param interfaces the interfaces to merge + * @param classLoader the ClassLoader to create the composite Class in + * @return the merged interface as Class + * @see java.lang.reflect.Proxy#getProxyClass + */ + public static Class createCompositeInterface(Class[] interfaces, ClassLoader classLoader) { + Assert.notEmpty(interfaces, "Interfaces must not be empty"); + Assert.notNull(classLoader, "ClassLoader must not be null"); + return Proxy.getProxyClass(classLoader, interfaces); + } + + /** + * Check whether the given class is visible in the given ClassLoader. + * @param clazz the class to check (typically an interface) + * @param classLoader the ClassLoader to check against (may be null, + * in which case this method will always return true) + */ + public static boolean isVisible(Class clazz, ClassLoader classLoader) { + if (classLoader == null) { + return true; + } + try { + Class actualClass = classLoader.loadClass(clazz.getName()); + return (clazz == actualClass); + // Else: different interface class found... + } + catch (ClassNotFoundException ex) { + // No interface class found... + return false; + } + } + +} Index: 3rdParty_sources/spring/org/springframework/util/CollectionUtils.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/util/CollectionUtils.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/util/CollectionUtils.java 17 Aug 2012 15:16:10 -0000 1.1 @@ -0,0 +1,275 @@ +/* + * 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.util; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Enumeration; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Properties; + +/** + * Miscellaneous collection utility methods. + * Mainly for internal use within the framework. + * + * @author Juergen Hoeller + * @author Rob Harrop + * @since 1.1.3 + */ +public abstract class CollectionUtils { + + /** + * Return true if the supplied Collection is null + * or empty. Otherwise, return false. + * @param collection the Collection to check + * @return whether the given Collection is empty + */ + public static boolean isEmpty(Collection collection) { + return (collection == null || collection.isEmpty()); + } + + /** + * Return true if the supplied Map is null + * or empty. Otherwise, return false. + * @param map the Map to check + * @return whether the given Map is empty + */ + public static boolean isEmpty(Map map) { + return (map == null || map.isEmpty()); + } + + /** + * Convert the supplied array into a List. A primitive array gets + * converted into a List of the appropriate wrapper type. + *

A null source value will be converted to an + * empty List. + * @param source the (potentially primitive) array + * @return the converted List result + * @see ObjectUtils#toObjectArray(Object) + */ + public static List arrayToList(Object source) { + return Arrays.asList(ObjectUtils.toObjectArray(source)); + } + + /** + * Merge the given array into the given Collection. + * @param array the array to merge (may be null) + * @param collection the target Collection to merge the array into + */ + public static void mergeArrayIntoCollection(Object array, Collection collection) { + if (collection == null) { + throw new IllegalArgumentException("Collection must not be null"); + } + Object[] arr = ObjectUtils.toObjectArray(array); + for (int i = 0; i < arr.length; i++) { + collection.add(arr[i]); + } + } + + /** + * Merge the given Properties instance into the given Map, + * copying all properties (key-value pairs) over. + *

Uses Properties.propertyNames() to even catch + * default properties linked into the original Properties instance. + * @param props the Properties instance to merge (may be null) + * @param map the target Map to merge the properties into + */ + public static void mergePropertiesIntoMap(Properties props, Map map) { + if (map == null) { + throw new IllegalArgumentException("Map must not be null"); + } + if (props != null) { + for (Enumeration en = props.propertyNames(); en.hasMoreElements();) { + String key = (String) en.nextElement(); + map.put(key, props.getProperty(key)); + } + } + } + + + /** + * Check whether the given Iterator contains the given element. + * @param iterator the Iterator to check + * @param element the element to look for + * @return true if found, false else + */ + public static boolean contains(Iterator iterator, Object element) { + if (iterator != null) { + while (iterator.hasNext()) { + Object candidate = iterator.next(); + if (ObjectUtils.nullSafeEquals(candidate, element)) { + return true; + } + } + } + return false; + } + + /** + * Check whether the given Enumeration contains the given element. + * @param enumeration the Enumeration to check + * @param element the element to look for + * @return true if found, false else + */ + public static boolean contains(Enumeration enumeration, Object element) { + if (enumeration != null) { + while (enumeration.hasMoreElements()) { + Object candidate = enumeration.nextElement(); + if (ObjectUtils.nullSafeEquals(candidate, element)) { + return true; + } + } + } + return false; + } + + /** + * Check whether the given Collection contains the given element instance. + *

Enforces the given instance to be present, rather than returning + * true for an equal element as well. + * @param collection the Collection to check + * @param element the element to look for + * @return true if found, false else + */ + public static boolean containsInstance(Collection collection, Object element) { + if (collection != null) { + for (Iterator it = collection.iterator(); it.hasNext();) { + Object candidate = it.next(); + if (candidate == element) { + return true; + } + } + } + return false; + } + + /** + * Return true if any element in 'candidates' is + * contained in 'source'; otherwise returns false. + * @param source the source Collection + * @param candidates the candidates to search for + * @return whether any of the candidates has been found + */ + public static boolean containsAny(Collection source, Collection candidates) { + if (isEmpty(source) || isEmpty(candidates)) { + return false; + } + for (Iterator it = candidates.iterator(); it.hasNext();) { + if (source.contains(it.next())) { + return true; + } + } + return false; + } + + /** + * Return the first element in 'candidates' that is contained in + * 'source'. If no element in 'candidates' is present in + * 'source' returns null. Iteration order is + * {@link Collection} implementation specific. + * @param source the source Collection + * @param candidates the candidates to search for + * @return the first present object, or null if not found + */ + public static Object findFirstMatch(Collection source, Collection candidates) { + if (isEmpty(source) || isEmpty(candidates)) { + return null; + } + for (Iterator it = candidates.iterator(); it.hasNext();) { + Object candidate = it.next(); + if (source.contains(candidate)) { + return candidate; + } + } + return null; + } + + /** + * Find a single value of the given type in the given Collection. + * @param collection the Collection to search + * @param type the type to look for + * @return a value of the given type found if there is a clear match, + * or null if none or more than one such value found + */ + public static Object findValueOfType(Collection collection, Class type) { + if (isEmpty(collection)) { + return null; + } + Object value = null; + for (Iterator it = collection.iterator(); it.hasNext();) { + Object obj = it.next(); + if (type == null || type.isInstance(obj)) { + if (value != null) { + // More than one value found... no clear single value. + return null; + } + value = obj; + } + } + return value; + } + + /** + * Find a single value of one of the given types in the given Collection: + * searching the Collection for a value of the first type, then + * searching for a value of the second type, etc. + * @param collection the collection to search + * @param types the types to look for, in prioritized order + * @return a value of one of the given types found if there is a clear match, + * or null if none or more than one such value found + */ + public static Object findValueOfType(Collection collection, Class[] types) { + if (isEmpty(collection) || ObjectUtils.isEmpty(types)) { + return null; + } + for (int i = 0; i < types.length; i++) { + Object value = findValueOfType(collection, types[i]); + if (value != null) { + return value; + } + } + return null; + } + + /** + * Determine whether the given Collection only contains a single unique object. + * @param collection the Collection to check + * @return true if the collection contains a single reference or + * multiple references to the same instance, false else + */ + public static boolean hasUniqueObject(Collection collection) { + if (isEmpty(collection)) { + return false; + } + boolean hasCandidate = false; + Object candidate = null; + for (Iterator it = collection.iterator(); it.hasNext();) { + Object elem = it.next(); + if (!hasCandidate) { + hasCandidate = true; + candidate = elem; + } + else if (candidate != elem) { + return false; + } + } + return true; + } + +} Index: 3rdParty_sources/spring/org/springframework/util/CommonsLogWriter.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/util/CommonsLogWriter.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/util/CommonsLogWriter.java 17 Aug 2012 15:16:09 -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.util; + +import java.io.Writer; + +import org.apache.commons.logging.Log; + +/** + * java.io.Writer adapter for a Commons Logging Log. + * + * @author Juergen Hoeller + * @since 2.5.1 + */ +public class CommonsLogWriter extends Writer { + + private final Log logger; + + private final StringBuffer buffer = new StringBuffer(); + + + /** + * Create a new CommonsLogWriter for the given Commons Logging logger. + * @param logger the Commons Logging logger to write to + */ + public CommonsLogWriter(Log logger) { + Assert.notNull(logger, "Logger must not be null"); + this.logger = logger; + } + + + public void write(char ch) { + if (ch == '\n' && this.buffer.length() > 0) { + this.logger.debug(this.buffer.toString()); + this.buffer.setLength(0); + } + else { + this.buffer.append((char) ch); + } + } + + public void write(char[] buffer, int offset, int length) { + for (int i = 0; i < length; i++) { + char ch = buffer[offset + i]; + if (ch == '\n' && this.buffer.length() > 0) { + this.logger.debug(this.buffer.toString()); + this.buffer.setLength(0); + } + else { + this.buffer.append((char) ch); + } + } + } + + public void flush() { + } + + public void close() { + } + +} Index: 3rdParty_sources/spring/org/springframework/util/ConcurrencyThrottleSupport.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/util/ConcurrencyThrottleSupport.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/util/ConcurrencyThrottleSupport.java 17 Aug 2012 15:16:09 -0000 1.1 @@ -0,0 +1,169 @@ +/* + * 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.util; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.Serializable; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * Support class for throttling concurrent access to a specific resource. + * + *

Designed for use as a base class, with the subclass invoking + * the {@link #beforeAccess()} and {@link #afterAccess()} methods at + * appropriate points of its workflow. Note that afterAccess + * should usually be called in a finally block! + * + *

The default concurrency limit of this support class is -1 + * ("unbounded concurrency"). Subclasses may override this default; + * check the javadoc of the concrete class that you're using. + * + * @author Juergen Hoeller + * @since 1.2.5 + * @see #setConcurrencyLimit + * @see #beforeAccess() + * @see #afterAccess() + * @see org.springframework.aop.interceptor.ConcurrencyThrottleInterceptor + * @see java.io.Serializable + */ +public abstract class ConcurrencyThrottleSupport implements Serializable { + + /** + * Permit any number of concurrent invocations: that is, don't throttle concurrency. + */ + public static final int UNBOUNDED_CONCURRENCY = -1; + + /** + * Switch concurrency 'off': that is, don't allow any concurrent invocations. + */ + public static final int NO_CONCURRENCY = 0; + + + /** Transient to optimize serialization */ + protected transient Log logger = LogFactory.getLog(getClass()); + + private transient Object monitor = new Object(); + + private int concurrencyLimit = UNBOUNDED_CONCURRENCY; + + private int concurrencyCount = 0; + + + /** + * Set the maximum number of concurrent access attempts allowed. + * -1 indicates unbounded concurrency. + *

In principle, this limit can be changed at runtime, + * although it is generally designed as a config time setting. + *

NOTE: Do not switch between -1 and any concrete limit at runtime, + * as this will lead to inconsistent concurrency counts: A limit + * of -1 effectively turns off concurrency counting completely. + */ + public void setConcurrencyLimit(int concurrencyLimit) { + this.concurrencyLimit = concurrencyLimit; + } + + /** + * Return the maximum number of concurrent access attempts allowed. + */ + public int getConcurrencyLimit() { + return this.concurrencyLimit; + } + + /** + * Return whether this throttle is currently active. + * @return true if the concurrency limit for this instance is active + * @see #getConcurrencyLimit() + */ + public boolean isThrottleActive() { + return (this.concurrencyLimit > 0); + } + + + /** + * To be invoked before the main execution logic of concrete subclasses. + *

This implementation applies the concurrency throttle. + * @see #afterAccess() + */ + protected void beforeAccess() { + if (this.concurrencyLimit == NO_CONCURRENCY) { + throw new IllegalStateException( + "Currently no invocations allowed - concurrency limit set to NO_CONCURRENCY"); + } + if (this.concurrencyLimit > 0) { + boolean debug = logger.isDebugEnabled(); + synchronized (this.monitor) { + boolean interrupted = false; + while (this.concurrencyCount >= this.concurrencyLimit) { + if (interrupted) { + throw new IllegalStateException("Thread was interrupted while waiting for invocation access, " + + "but concurrency limit still does not allow for entering"); + } + if (debug) { + logger.debug("Concurrency count " + this.concurrencyCount + + " has reached limit " + this.concurrencyLimit + " - blocking"); + } + try { + this.monitor.wait(); + } + catch (InterruptedException ex) { + // Re-interrupt current thread, to allow other threads to react. + Thread.currentThread().interrupt(); + interrupted = true; + } + } + if (debug) { + logger.debug("Entering throttle at concurrency count " + this.concurrencyCount); + } + this.concurrencyCount++; + } + } + } + + /** + * To be invoked after the main execution logic of concrete subclasses. + * @see #beforeAccess() + */ + protected void afterAccess() { + if (this.concurrencyLimit >= 0) { + synchronized (this.monitor) { + this.concurrencyCount--; + if (logger.isDebugEnabled()) { + logger.debug("Returning from throttle at concurrency count " + this.concurrencyCount); + } + this.monitor.notify(); + } + } + } + + + //--------------------------------------------------------------------- + // Serialization support + //--------------------------------------------------------------------- + + private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException { + // Rely on default serialization, just initialize state after deserialization. + ois.defaultReadObject(); + + // Initialize transient fields. + this.logger = LogFactory.getLog(getClass()); + this.monitor = new Object(); + } + +} Index: 3rdParty_sources/spring/org/springframework/util/CustomizableThreadCreator.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/util/CustomizableThreadCreator.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/util/CustomizableThreadCreator.java 17 Aug 2012 15:16:10 -0000 1.1 @@ -0,0 +1,177 @@ +/* + * 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.util; + +/** + * Simple customizable helper class for creating threads. Provides various + * bean properties, such as thread name prefix, thread priority, etc. + * + *

Serves as base class for thread factories such as + * {@link org.springframework.scheduling.concurrent.CustomizableThreadFactory}. + * + * @author Juergen Hoeller + * @since 2.0.3 + * @see org.springframework.scheduling.concurrent.CustomizableThreadFactory + */ +public class CustomizableThreadCreator { + + private String threadNamePrefix; + + private int threadPriority = Thread.NORM_PRIORITY; + + private boolean daemon = false; + + private ThreadGroup threadGroup; + + private int threadCount = 0; + + private final Object threadCountMonitor = new Object(); + + + /** + * Create a new CustomizableThreadCreator with default thread name prefix. + */ + public CustomizableThreadCreator() { + this.threadNamePrefix = getDefaultThreadNamePrefix(); + } + + /** + * Create a new CustomizableThreadCreator with the given thread name prefix. + * @param threadNamePrefix the prefix to use for the names of newly created threads + */ + public CustomizableThreadCreator(String threadNamePrefix) { + this.threadNamePrefix = (threadNamePrefix != null ? threadNamePrefix : getDefaultThreadNamePrefix()); + } + + + /** + * Specify the prefix to use for the names of newly created threads. + * Default is "SimpleAsyncTaskExecutor-". + */ + public void setThreadNamePrefix(String threadNamePrefix) { + this.threadNamePrefix = (threadNamePrefix != null ? threadNamePrefix : getDefaultThreadNamePrefix()); + } + + /** + * Return the thread name prefix to use for the names of newly + * created threads. + */ + public String getThreadNamePrefix() { + return this.threadNamePrefix; + } + + /** + * Set the priority of the threads that this factory creates. + * Default is 5. + * @see java.lang.Thread#NORM_PRIORITY + */ + public void setThreadPriority(int threadPriority) { + this.threadPriority = threadPriority; + } + + /** + * Return the priority of the threads that this factory creates. + */ + public int getThreadPriority() { + return this.threadPriority; + } + + /** + * Set whether this factory is supposed to create daemon threads, + * just executing as long as the application itself is running. + *

Default is "false": Concrete factories usually support explicit + * cancelling. Hence, if the application shuts down, Runnables will + * by default finish their execution. + *

Specify "true" for eager shutdown of threads which still + * actively execute a Runnable. + * @see java.lang.Thread#setDaemon + */ + public void setDaemon(boolean daemon) { + this.daemon = daemon; + } + + /** + * Return whether this factory should create daemon threads. + */ + public boolean isDaemon() { + return this.daemon; + } + + /** + * Specify the name of the thread group that threads should be created in. + * @see #setThreadGroup + */ + public void setThreadGroupName(String name) { + this.threadGroup = new ThreadGroup(name); + } + + /** + * Specify the thread group that threads should be created in. + * @see #setThreadGroupName + */ + public void setThreadGroup(ThreadGroup threadGroup) { + this.threadGroup = threadGroup; + } + + /** + * Return the thread group that threads should be created in + * (or null) for the default group. + */ + public ThreadGroup getThreadGroup() { + return this.threadGroup; + } + + + /** + * Template method for the creation of a Thread. + *

Default implementation creates a new Thread for the given + * Runnable, applying an appropriate thread name. + * @param runnable the Runnable to execute + * @see #nextThreadName() + */ + public Thread createThread(Runnable runnable) { + Thread thread = new Thread(getThreadGroup(), runnable, nextThreadName()); + thread.setPriority(getThreadPriority()); + thread.setDaemon(isDaemon()); + return thread; + } + + /** + * Return the thread name to use for a newly created thread. + *

Default implementation returns the specified thread name prefix + * with an increasing thread count appended: for example, + * "SimpleAsyncTaskExecutor-0". + * @see #getThreadNamePrefix() + */ + protected String nextThreadName() { + int threadNumber = 0; + synchronized (this.threadCountMonitor) { + this.threadCount++; + threadNumber = this.threadCount; + } + return getThreadNamePrefix() + threadNumber; + } + + /** + * Build the default thread name prefix for this factory. + * @return the default thread name prefix (never null) + */ + protected String getDefaultThreadNamePrefix() { + return ClassUtils.getShortName(getClass()) + "-"; + } + +} Index: 3rdParty_sources/spring/org/springframework/util/DefaultPropertiesPersister.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/util/DefaultPropertiesPersister.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/util/DefaultPropertiesPersister.java 17 Aug 2012 15:16:10 -0000 1.1 @@ -0,0 +1,257 @@ +/* + * 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.util; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Reader; +import java.io.Writer; +import java.util.Date; +import java.util.Enumeration; +import java.util.Properties; + +/** + * Default implementation of the {@link PropertiesPersister} interface. + * Follows the native parsing of java.util.Properties. + * + *

Allows for reading from any Reader and writing to any Writer, for example + * to specify a charset for a properties file. This is a capability that standard + * java.util.Properties unfortunately lacks up until JDK 1.5: + * You can only load files using the ISO-8859-1 charset there. + * + *

Loading from and storing to a stream delegates to Properties.load + * and Properties.store, respectively, to be fully compatible with + * the Unicode conversion as implemented by the JDK Properties class. On JDK 1.6, + * Properties.load/store will also be used for readers/writers, + * effectively turning this class into a plain backwards compatibility adapter. + * + *

The persistence code that works with Reader/Writer follows the JDK's parsing + * strategy but does not implement Unicode conversion, because the Reader/Writer + * should already apply proper decoding/encoding of characters. If you use prefer + * to escape unicode characters in your properties files, do not specify + * an encoding for a Reader/Writer (like ReloadableResourceBundleMessageSource's + * "defaultEncoding" and "fileEncodings" properties). + * + *

As of Spring 1.2.2, this implementation also supports properties XML files, + * through the loadFromXml and storeToXml methods. + * The default implementations delegate to JDK 1.5's corresponding methods, + * throwing an exception if running on an older JDK. Those implementations + * could be subclassed to apply custom XML handling on JDK 1.4, for example. + * + * @author Juergen Hoeller + * @since 10.03.2004 + * @see java.util.Properties + * @see java.util.Properties#load + * @see java.util.Properties#store + * @see org.springframework.context.support.ReloadableResourceBundleMessageSource#setPropertiesPersister + * @see org.springframework.context.support.ReloadableResourceBundleMessageSource#setDefaultEncoding + * @see org.springframework.context.support.ReloadableResourceBundleMessageSource#setFileEncodings + */ +public class DefaultPropertiesPersister implements PropertiesPersister { + + // Determine whether Properties.load(Reader) is available (on JDK 1.6+) + private static final boolean loadFromReaderAvailable = + ClassUtils.hasMethod(Properties.class, "load", new Class[] {Reader.class}); + + // Determine whether Properties.store(Writer, String) is available (on JDK 1.6+) + private static final boolean storeToWriterAvailable = + ClassUtils.hasMethod(Properties.class, "store", new Class[] {Writer.class, String.class}); + + + public void load(Properties props, InputStream is) throws IOException { + props.load(is); + } + + public void load(Properties props, Reader reader) throws IOException { + if (loadFromReaderAvailable) { + // On JDK 1.6+ + props.load(reader); + } + else { + // Fall back to manual parsing. + doLoad(props, reader); + } + } + + protected void doLoad(Properties props, Reader reader) throws IOException { + BufferedReader in = new BufferedReader(reader); + while (true) { + String line = in.readLine(); + if (line == null) { + return; + } + line = StringUtils.trimLeadingWhitespace(line); + if (line.length() > 0) { + char firstChar = line.charAt(0); + if (firstChar != '#' && firstChar != '!') { + while (endsWithContinuationMarker(line)) { + String nextLine = in.readLine(); + line = line.substring(0, line.length() - 1); + if (nextLine != null) { + line += StringUtils.trimLeadingWhitespace(nextLine); + } + } + int separatorIndex = line.indexOf("="); + if (separatorIndex == -1) { + separatorIndex = line.indexOf(":"); + } + String key = (separatorIndex != -1 ? line.substring(0, separatorIndex) : line); + String value = (separatorIndex != -1) ? line.substring(separatorIndex + 1) : ""; + key = StringUtils.trimTrailingWhitespace(key); + value = StringUtils.trimLeadingWhitespace(value); + props.put(unescape(key), unescape(value)); + } + } + } + } + + protected boolean endsWithContinuationMarker(String line) { + boolean evenSlashCount = true; + int index = line.length() - 1; + while (index >= 0 && line.charAt(index) == '\\') { + evenSlashCount = !evenSlashCount; + index--; + } + return !evenSlashCount; + } + + protected String unescape(String str) { + StringBuffer outBuffer = new StringBuffer(str.length()); + for (int index = 0; index < str.length();) { + char c = str.charAt(index++); + if (c == '\\') { + c = str.charAt(index++); + if (c == 't') { + c = '\t'; + } + else if (c == 'r') { + c = '\r'; + } + else if (c == 'n') { + c = '\n'; + } + else if (c == 'f') { + c = '\f'; + } + } + outBuffer.append(c); + } + return outBuffer.toString(); + } + + + public void store(Properties props, OutputStream os, String header) throws IOException { + props.store(os, header); + } + + public void store(Properties props, Writer writer, String header) throws IOException { + if (storeToWriterAvailable) { + // On JDK 1.6+ + props.store(writer, header); + } + else { + // Fall back to manual parsing. + doStore(props, writer, header); + } + } + + protected void doStore(Properties props, Writer writer, String header) throws IOException { + BufferedWriter out = new BufferedWriter(writer); + if (header != null) { + out.write("#" + header); + out.newLine(); + } + out.write("#" + new Date()); + out.newLine(); + for (Enumeration keys = props.keys(); keys.hasMoreElements();) { + String key = (String) keys.nextElement(); + String val = props.getProperty(key); + out.write(escape(key, true) + "=" + escape(val, false)); + out.newLine(); + } + out.flush(); + } + + protected String escape(String str, boolean isKey) { + int len = str.length(); + StringBuffer outBuffer = new StringBuffer(len * 2); + for (int index = 0; index < len; index++) { + char c = str.charAt(index); + switch (c) { + case ' ': + if (index == 0 || isKey) { + outBuffer.append('\\'); + } + outBuffer.append(' '); + break; + case '\\': + outBuffer.append("\\\\"); + break; + case '\t': + outBuffer.append("\\t"); + break; + case '\n': + outBuffer.append("\\n"); + break; + case '\r': + outBuffer.append("\\r"); + break; + case '\f': + outBuffer.append("\\f"); + break; + default: + if ("=: \t\r\n\f#!".indexOf(c) != -1) { + outBuffer.append('\\'); + } + outBuffer.append(c); + } + } + return outBuffer.toString(); + } + + + public void loadFromXml(Properties props, InputStream is) throws IOException { + try { + props.loadFromXML(is); + } + catch (NoSuchMethodError err) { + throw new IOException("Cannot load properties XML file - not running on JDK 1.5+: " + err.getMessage()); + } + } + + public void storeToXml(Properties props, OutputStream os, String header) throws IOException { + try { + props.storeToXML(os, header); + } + catch (NoSuchMethodError err) { + throw new IOException("Cannot store properties XML file - not running on JDK 1.5+: " + err.getMessage()); + } + } + + public void storeToXml(Properties props, OutputStream os, String header, String encoding) throws IOException { + try { + props.storeToXML(os, header, encoding); + } + catch (NoSuchMethodError err) { + throw new IOException("Cannot store properties XML file - not running on JDK 1.5+: " + err.getMessage()); + } + } + +} Index: 3rdParty_sources/spring/org/springframework/util/FileCopyUtils.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/util/FileCopyUtils.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/util/FileCopyUtils.java 17 Aug 2012 15:16:10 -0000 1.1 @@ -0,0 +1,244 @@ +/* + * 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.util; + +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Reader; +import java.io.StringWriter; +import java.io.Writer; + +/** + * Simple utility methods for file and stream copying. + * All copy methods use a block size of 4096 bytes, + * and close all affected streams when done. + * + *

Mainly for use within the framework, + * but also useful for application code. + * + * @author Juergen Hoeller + * @since 06.10.2003 + */ +public abstract class FileCopyUtils { + + public static final int BUFFER_SIZE = 4096; + + + //--------------------------------------------------------------------- + // Copy methods for java.io.File + //--------------------------------------------------------------------- + + /** + * Copy the contents of the given input File to the given output File. + * @param in the file to copy from + * @param out the file to copy to + * @return the number of bytes copied + * @throws IOException in case of I/O errors + */ + public static int copy(File in, File out) throws IOException { + Assert.notNull(in, "No input File specified"); + Assert.notNull(out, "No output File specified"); + return copy(new BufferedInputStream(new FileInputStream(in)), + new BufferedOutputStream(new FileOutputStream(out))); + } + + /** + * Copy the contents of the given byte array to the given output File. + * @param in the byte array to copy from + * @param out the file to copy to + * @throws IOException in case of I/O errors + */ + public static void copy(byte[] in, File out) throws IOException { + Assert.notNull(in, "No input byte array specified"); + Assert.notNull(out, "No output File specified"); + ByteArrayInputStream inStream = new ByteArrayInputStream(in); + OutputStream outStream = new BufferedOutputStream(new FileOutputStream(out)); + copy(inStream, outStream); + } + + /** + * Copy the contents of the given input File into a new byte array. + * @param in the file to copy from + * @return the new byte array that has been copied to + * @throws IOException in case of I/O errors + */ + public static byte[] copyToByteArray(File in) throws IOException { + Assert.notNull(in, "No input File specified"); + return copyToByteArray(new BufferedInputStream(new FileInputStream(in))); + } + + + //--------------------------------------------------------------------- + // Copy methods for java.io.InputStream / java.io.OutputStream + //--------------------------------------------------------------------- + + /** + * Copy the contents of the given InputStream to the given OutputStream. + * Closes both streams when done. + * @param in the stream to copy from + * @param out the stream to copy to + * @return the number of bytes copied + * @throws IOException in case of I/O errors + */ + public static int copy(InputStream in, OutputStream out) throws IOException { + Assert.notNull(in, "No InputStream specified"); + Assert.notNull(out, "No OutputStream specified"); + try { + int byteCount = 0; + byte[] buffer = new byte[BUFFER_SIZE]; + int bytesRead = -1; + while ((bytesRead = in.read(buffer)) != -1) { + out.write(buffer, 0, bytesRead); + byteCount += bytesRead; + } + out.flush(); + return byteCount; + } + finally { + try { + in.close(); + } + catch (IOException ex) { + } + try { + out.close(); + } + catch (IOException ex) { + } + } + } + + /** + * Copy the contents of the given byte array to the given OutputStream. + * Closes the stream when done. + * @param in the byte array to copy from + * @param out the OutputStream to copy to + * @throws IOException in case of I/O errors + */ + public static void copy(byte[] in, OutputStream out) throws IOException { + Assert.notNull(in, "No input byte array specified"); + Assert.notNull(out, "No OutputStream specified"); + try { + out.write(in); + } + finally { + try { + out.close(); + } + catch (IOException ex) { + } + } + } + + /** + * Copy the contents of the given InputStream into a new byte array. + * Closes the stream when done. + * @param in the stream to copy from + * @return the new byte array that has been copied to + * @throws IOException in case of I/O errors + */ + public static byte[] copyToByteArray(InputStream in) throws IOException { + ByteArrayOutputStream out = new ByteArrayOutputStream(BUFFER_SIZE); + copy(in, out); + return out.toByteArray(); + } + + + //--------------------------------------------------------------------- + // Copy methods for java.io.Reader / java.io.Writer + //--------------------------------------------------------------------- + + /** + * Copy the contents of the given Reader to the given Writer. + * Closes both when done. + * @param in the Reader to copy from + * @param out the Writer to copy to + * @return the number of characters copied + * @throws IOException in case of I/O errors + */ + public static int copy(Reader in, Writer out) throws IOException { + Assert.notNull(in, "No Reader specified"); + Assert.notNull(out, "No Writer specified"); + try { + int byteCount = 0; + char[] buffer = new char[BUFFER_SIZE]; + int bytesRead = -1; + while ((bytesRead = in.read(buffer)) != -1) { + out.write(buffer, 0, bytesRead); + byteCount += bytesRead; + } + out.flush(); + return byteCount; + } + finally { + try { + in.close(); + } + catch (IOException ex) { + } + try { + out.close(); + } + catch (IOException ex) { + } + } + } + + /** + * Copy the contents of the given String to the given output Writer. + * Closes the write when done. + * @param in the String to copy from + * @param out the Writer to copy to + * @throws IOException in case of I/O errors + */ + public static void copy(String in, Writer out) throws IOException { + Assert.notNull(in, "No input String specified"); + Assert.notNull(out, "No Writer specified"); + try { + out.write(in); + } + finally { + try { + out.close(); + } + catch (IOException ex) { + } + } + } + + /** + * Copy the contents of the given Reader into a String. + * Closes the reader when done. + * @param in the reader to copy from + * @return the String that has been copied to + * @throws IOException in case of I/O errors + */ + public static String copyToString(Reader in) throws IOException { + StringWriter out = new StringWriter(); + copy(in, out); + return out.toString(); + } + +} Index: 3rdParty_sources/spring/org/springframework/util/FileSystemUtils.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/util/FileSystemUtils.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/util/FileSystemUtils.java 17 Aug 2012 15:16:10 -0000 1.1 @@ -0,0 +1,102 @@ +/* + * 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.util; + +import java.io.File; +import java.io.IOException; + +/** + * Utility methods for working with the file system. + * + * @author Rob Harrop + * @author Juergen Hoeller + * @since 2.5.3 + */ +public abstract class FileSystemUtils { + + /** + * Delete the supplied {@link File} - for directories, + * recursively delete any nested directories or files as well. + * @param root the root File to delete + * @return true if the File was deleted, + * otherwise false + */ + public static boolean deleteRecursively(File root) { + if (root != null && root.exists()) { + if (root.isDirectory()) { + File[] children = root.listFiles(); + if (children != null) { + for (int i = 0; i < children.length; i++) { + deleteRecursively(children[i]); + } + } + } + return root.delete(); + } + return false; + } + + /** + * Recursively copy the contents of the src file/directory + * to the dest file/directory. + * @param src the source directory + * @param dest the destination directory + * @throws IOException in the case of I/O errors + */ + public static void copyRecursively(File src, File dest) throws IOException { + Assert.isTrue(src != null && (src.isDirectory() || src.isFile()), "Source File must denote a directory or file"); + Assert.notNull(dest, "Destination File must not be null"); + doCopyRecursively(src, dest); + } + + /** + * Actually copy the contents of the src file/directory + * to the dest file/directory. + * @param src the source directory + * @param dest the destination directory + * @throws IOException in the case of I/O errors + */ + private static void doCopyRecursively(File src, File dest) throws IOException { + if (src.isDirectory()) { + dest.mkdir(); + File[] entries = src.listFiles(); + if (entries == null) { + throw new IOException("Could not list files in directory: " + src); + } + for (int i = 0; i < entries.length; i++) { + File file = entries[i]; + doCopyRecursively(file, new File(dest, file.getName())); + } + } + else if (src.isFile()) { + try { + dest.createNewFile(); + } + catch (IOException ex) { + IOException ioex = new IOException("Failed to create file: " + dest); + ioex.initCause(ex); + throw ioex; + } + FileCopyUtils.copy(src, dest); + } + else { + // Special File handle: neither a file not a directory. + // Simply skip it when contained in nested directory... + } + } + +} Index: 3rdParty_sources/spring/org/springframework/util/Log4jConfigurer.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/util/Log4jConfigurer.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/util/Log4jConfigurer.java 17 Aug 2012 15:16:10 -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.util; + +import java.io.File; +import java.io.FileNotFoundException; +import java.net.URL; + +import org.apache.log4j.LogManager; +import org.apache.log4j.PropertyConfigurator; +import org.apache.log4j.xml.DOMConfigurator; + +/** + * Convenience class that features simple methods for custom log4j configuration. + * + *

Only needed for non-default log4j initialization, for example with a custom + * config location or a refresh interval. By default, log4j will simply read its + * configuration from a "log4j.properties" or "log4j.xml" file in the root of + * the classpath. + * + *

For web environments, the analogous Log4jWebConfigurer class can be found + * in the web package, reading in its configuration from context-params in + * web.xml. In a J2EE web application, log4j is usually set up + * via Log4jConfigListener or Log4jConfigServlet, delegating to + * Log4jWebConfigurer underneath. + * + * @author Juergen Hoeller + * @since 13.03.2003 + * @see org.springframework.web.util.Log4jWebConfigurer + * @see org.springframework.web.util.Log4jConfigListener + * @see org.springframework.web.util.Log4jConfigServlet + */ +public abstract class Log4jConfigurer { + + /** Pseudo URL prefix for loading from the class path: "classpath:" */ + public static final String CLASSPATH_URL_PREFIX = "classpath:"; + + /** Extension that indicates a log4j XML config file: ".xml" */ + public static final String XML_FILE_EXTENSION = ".xml"; + + + /** + * Initialize log4j from the given file location, with no config file refreshing. + * Assumes an XML file in case of a ".xml" file extension, and a properties file + * otherwise. + * @param location the location of the config file: either a "classpath:" location + * (e.g. "classpath:myLog4j.properties"), an absolute file URL + * (e.g. "file:C:/log4j.properties), or a plain absolute path in the file system + * (e.g. "C:/log4j.properties") + * @throws FileNotFoundException if the location specifies an invalid file path + */ + public static void initLogging(String location) throws FileNotFoundException { + String resolvedLocation = SystemPropertyUtils.resolvePlaceholders(location); + URL url = ResourceUtils.getURL(resolvedLocation); + if (resolvedLocation.toLowerCase().endsWith(XML_FILE_EXTENSION)) { + DOMConfigurator.configure(url); + } + else { + PropertyConfigurator.configure(url); + } + } + + /** + * Initialize log4j from the given location, with the given refresh interval + * for the config file. Assumes an XML file in case of a ".xml" file extension, + * and a properties file otherwise. + *

Log4j's watchdog thread will asynchronously check whether the timestamp + * of the config file has changed, using the given interval between checks. + * A refresh interval of 1000 milliseconds (one second), which allows to + * do on-demand log level changes with immediate effect, is not unfeasible. + *

WARNING: Log4j's watchdog thread does not terminate until VM shutdown; + * in particular, it does not terminate on LogManager shutdown. Therefore, it is + * recommended to not use config file refreshing in a production J2EE + * environment; the watchdog thread would not stop on application shutdown there. + * @param location the location of the config file: either a "classpath:" location + * (e.g. "classpath:myLog4j.properties"), an absolute file URL + * (e.g. "file:C:/log4j.properties), or a plain absolute path in the file system + * (e.g. "C:/log4j.properties") + * @param refreshInterval interval between config file refresh checks, in milliseconds + * @throws FileNotFoundException if the location specifies an invalid file path + */ + public static void initLogging(String location, long refreshInterval) throws FileNotFoundException { + String resolvedLocation = SystemPropertyUtils.resolvePlaceholders(location); + File file = ResourceUtils.getFile(resolvedLocation); + if (!file.exists()) { + throw new FileNotFoundException("Log4j config file [" + resolvedLocation + "] not found"); + } + if (resolvedLocation.toLowerCase().endsWith(XML_FILE_EXTENSION)) { + DOMConfigurator.configureAndWatch(file.getAbsolutePath(), refreshInterval); + } + else { + PropertyConfigurator.configureAndWatch(file.getAbsolutePath(), refreshInterval); + } + } + + /** + * Shut down log4j, properly releasing all file locks. + *

This isn't strictly necessary, but recommended for shutting down + * log4j in a scenario where the host VM stays alive (for example, when + * shutting down an application in a J2EE environment). + */ + public static void shutdownLogging() { + LogManager.shutdown(); + } + + /** + * Set the specified system property to the current working directory. + *

This can be used e.g. for test environments, for applications that leverage + * Log4jWebConfigurer's "webAppRootKey" support in a web environment. + * @param key system property key to use, as expected in Log4j configuration + * (for example: "demo.root", used as "${demo.root}/WEB-INF/demo.log") + * @see org.springframework.web.util.Log4jWebConfigurer + */ + public static void setWorkingDirSystemProperty(String key) { + System.setProperty(key, new File("").getAbsolutePath()); + } + +} Index: 3rdParty_sources/spring/org/springframework/util/MethodInvoker.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/util/MethodInvoker.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/util/MethodInvoker.java 17 Aug 2012 15:16:10 -0000 1.1 @@ -0,0 +1,327 @@ +/* + * 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.util; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; + +/** + * Helper class that allows for specifying a method to invoke in a declarative + * fashion, be it static or non-static. + * + *

Usage: Specify "targetClass"/"targetMethod" or "targetObject"/"targetMethod", + * optionally specify arguments, prepare the invoker. Afterwards, you may + * invoke the method any number of times, obtaining the invocation result. + * + *

Typically not used directly but via its subclasses + * {@link org.springframework.beans.factory.config.MethodInvokingFactoryBean} and + * {@link org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean}. + * + * @author Colin Sampaleanu + * @author Juergen Hoeller + * @since 19.02.2004 + * @see #prepare + * @see #invoke + * @see org.springframework.beans.factory.config.MethodInvokingFactoryBean + * @see org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean + */ +public class MethodInvoker { + + private Class targetClass; + + private Object targetObject; + + private String targetMethod; + + private String staticMethod; + + private Object[] arguments = new Object[0]; + + /** The method we will call */ + private Method methodObject; + + + /** + * Set the target class on which to call the target method. + * Only necessary when the target method is static; else, + * a target object needs to be specified anyway. + * @see #setTargetObject + * @see #setTargetMethod + */ + public void setTargetClass(Class targetClass) { + this.targetClass = targetClass; + } + + /** + * Return the target class on which to call the target method. + */ + public Class getTargetClass() { + return this.targetClass; + } + + /** + * Set the target object on which to call the target method. + * Only necessary when the target method is not static; + * else, a target class is sufficient. + * @see #setTargetClass + * @see #setTargetMethod + */ + public void setTargetObject(Object targetObject) { + this.targetObject = targetObject; + if (targetObject != null) { + this.targetClass = targetObject.getClass(); + } + } + + /** + * Return the target object on which to call the target method. + */ + public Object getTargetObject() { + return this.targetObject; + } + + /** + * Set the name of the method to be invoked. + * Refers to either a static method or a non-static method, + * depending on a target object being set. + * @see #setTargetClass + * @see #setTargetObject + */ + public void setTargetMethod(String targetMethod) { + this.targetMethod = targetMethod; + } + + /** + * Return the name of the method to be invoked. + */ + public String getTargetMethod() { + return this.targetMethod; + } + + /** + * Set a fully qualified static method name to invoke, + * e.g. "example.MyExampleClass.myExampleMethod". + * Convenient alternative to specifying targetClass and targetMethod. + * @see #setTargetClass + * @see #setTargetMethod + */ + public void setStaticMethod(String staticMethod) { + this.staticMethod = staticMethod; + } + + /** + * Set arguments for the method invocation. If this property is not set, + * or the Object array is of length 0, a method with no arguments is assumed. + */ + public void setArguments(Object[] arguments) { + this.arguments = (arguments != null ? arguments : new Object[0]); + } + + /** + * Return the arguments for the method invocation. + */ + public Object[] getArguments() { + return this.arguments; + } + + + /** + * Prepare the specified method. + * The method can be invoked any number of times afterwards. + * @see #getPreparedMethod + * @see #invoke + */ + public void prepare() throws ClassNotFoundException, NoSuchMethodException { + if (this.staticMethod != null) { + int lastDotIndex = this.staticMethod.lastIndexOf('.'); + if (lastDotIndex == -1 || lastDotIndex == this.staticMethod.length()) { + throw new IllegalArgumentException( + "staticMethod must be a fully qualified class plus method name: " + + "e.g. 'example.MyExampleClass.myExampleMethod'"); + } + String className = this.staticMethod.substring(0, lastDotIndex); + String methodName = this.staticMethod.substring(lastDotIndex + 1); + this.targetClass = resolveClassName(className); + this.targetMethod = methodName; + } + + Class targetClass = getTargetClass(); + String targetMethod = getTargetMethod(); + if (targetClass == null) { + throw new IllegalArgumentException("Either 'targetClass' or 'targetObject' is required"); + } + if (targetMethod == null) { + throw new IllegalArgumentException("Property 'targetMethod' is required"); + } + + Object[] arguments = getArguments(); + Class[] argTypes = new Class[arguments.length]; + for (int i = 0; i < arguments.length; ++i) { + argTypes[i] = (arguments[i] != null ? arguments[i].getClass() : Object.class); + } + + // Try to get the exact method first. + try { + this.methodObject = targetClass.getMethod(targetMethod, argTypes); + } + catch (NoSuchMethodException ex) { + // Just rethrow exception if we can't get any match. + this.methodObject = findMatchingMethod(); + if (this.methodObject == null) { + throw ex; + } + } + } + + /** + * Resolve the given class name into a Class. + *

The default implementations uses ClassUtils.forName, + * using the thread context class loader. + * @param className the class name to resolve + * @return the resolved Class + * @throws ClassNotFoundException if the class name was invalid + */ + protected Class resolveClassName(String className) throws ClassNotFoundException { + return ClassUtils.forName(className); + } + + /** + * Find a matching method with the specified name for the specified arguments. + * @return a matching method, or null if none + * @see #getTargetClass() + * @see #getTargetMethod() + * @see #getArguments() + */ + protected Method findMatchingMethod() { + String targetMethod = getTargetMethod(); + Object[] arguments = getArguments(); + int argCount = arguments.length; + + Method[] candidates = ReflectionUtils.getAllDeclaredMethods(getTargetClass()); + int minTypeDiffWeight = Integer.MAX_VALUE; + Method matchingMethod = null; + + for (int i = 0; i < candidates.length; i++) { + Method candidate = candidates[i]; + if (candidate.getName().equals(targetMethod)) { + Class[] paramTypes = candidate.getParameterTypes(); + if (paramTypes.length == argCount) { + int typeDiffWeight = getTypeDifferenceWeight(paramTypes, arguments); + if (typeDiffWeight < minTypeDiffWeight) { + minTypeDiffWeight = typeDiffWeight; + matchingMethod = candidate; + } + } + } + } + + return matchingMethod; + } + + /** + * Return the prepared Method object that will be invoked. + *

Can for example be used to determine the return type. + * @return the prepared Method object (never null) + * @throws IllegalStateException if the invoker hasn't been prepared yet + * @see #prepare + * @see #invoke + */ + public Method getPreparedMethod() throws IllegalStateException { + if (this.methodObject == null) { + throw new IllegalStateException("prepare() must be called prior to invoke() on MethodInvoker"); + } + return this.methodObject; + } + + /** + * Return whether this invoker has been prepared already, + * i.e. whether it allows access to {@link #getPreparedMethod()} already. + */ + public boolean isPrepared() { + return (this.methodObject != null); + } + + /** + * Invoke the specified method. + *

The invoker needs to have been prepared before. + * @return the object (possibly null) returned by the method invocation, + * or null if the method has a void return type + * @throws InvocationTargetException if the target method threw an exception + * @throws IllegalAccessException if the target method couldn't be accessed + * @see #prepare + */ + public Object invoke() throws InvocationTargetException, IllegalAccessException { + // In the static case, target will simply be null. + Object targetObject = getTargetObject(); + Method preparedMethod = getPreparedMethod(); + if (targetObject == null && !Modifier.isStatic(preparedMethod.getModifiers())) { + throw new IllegalArgumentException("Target method must not be non-static without a target"); + } + ReflectionUtils.makeAccessible(preparedMethod); + return preparedMethod.invoke(targetObject, getArguments()); + } + + + /** + * Algorithm that judges the match between the declared parameter types of a candidate method + * and a specific list of arguments that this method is supposed to be invoked with. + *

Determines a weight that represents the class hierarchy difference between types and + * arguments. A direct match, i.e. type Integer -> arg of class Integer, does not increase + * the result - all direct matches means weight 0. A match between type Object and arg of + * class Integer would increase the weight by 2, due to the superclass 2 steps up in the + * hierarchy (i.e. Object) being the last one that still matches the required type Object. + * Type Number and class Integer would increase the weight by 1 accordingly, due to the + * superclass 1 step up the hierarchy (i.e. Number) still matching the required type Number. + * Therefore, with an arg of type Integer, a constructor (Integer) would be preferred to a + * constructor (Number) which would in turn be preferred to a constructor (Object). + * All argument weights get accumulated. + * @param paramTypes the parameter types to match + * @param args the arguments to match + * @return the accumulated weight for all arguments + */ + public static int getTypeDifferenceWeight(Class[] paramTypes, Object[] args) { + int result = 0; + for (int i = 0; i < paramTypes.length; i++) { + if (!ClassUtils.isAssignableValue(paramTypes[i], args[i])) { + return Integer.MAX_VALUE; + } + if (args[i] != null) { + Class paramType = paramTypes[i]; + Class superClass = args[i].getClass().getSuperclass(); + while (superClass != null) { + if (paramType.equals(superClass)) { + result = result + 2; + superClass = null; + } + else if (ClassUtils.isAssignable(paramType, superClass)) { + result = result + 2; + superClass = superClass.getSuperclass(); + } + else { + superClass = null; + } + } + if (paramType.isInterface()) { + result = result + 1; + } + } + } + return result; + } + +} Index: 3rdParty_sources/spring/org/springframework/util/NumberUtils.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/util/NumberUtils.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/util/NumberUtils.java 17 Aug 2012 15:16:10 -0000 1.1 @@ -0,0 +1,273 @@ +/* + * 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.util; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.text.DecimalFormat; +import java.text.NumberFormat; +import java.text.ParseException; + +/** + * Miscellaneous utility methods for number conversion and parsing. + * Mainly for internal use within the framework; consider Jakarta's + * Commons Lang for a more comprehensive suite of string utilities. + * + * @author Juergen Hoeller + * @author Rob Harrop + * @since 1.1.2 + */ +public abstract class NumberUtils { + + private static final boolean decimalFormatSupportsBigDecimal = + ClassUtils.hasMethod(DecimalFormat.class, "setParseBigDecimal", new Class[] {boolean.class}); + + + /** + * Convert the given number into an instance of the given target class. + * @param number the number to convert + * @param targetClass the target class to convert to + * @return the converted number + * @throws IllegalArgumentException if the target class is not supported + * (i.e. not a standard Number subclass as included in the JDK) + * @see java.lang.Byte + * @see java.lang.Short + * @see java.lang.Integer + * @see java.lang.Long + * @see java.math.BigInteger + * @see java.lang.Float + * @see java.lang.Double + * @see java.math.BigDecimal + */ + public static Number convertNumberToTargetClass(Number number, Class targetClass) + throws IllegalArgumentException { + + Assert.notNull(number, "Number must not be null"); + Assert.notNull(targetClass, "Target class must not be null"); + + if (targetClass.isInstance(number)) { + return number; + } + else if (targetClass.equals(Byte.class)) { + long value = number.longValue(); + if (value < Byte.MIN_VALUE || value > Byte.MAX_VALUE) { + raiseOverflowException(number, targetClass); + } + return new Byte(number.byteValue()); + } + else if (targetClass.equals(Short.class)) { + long value = number.longValue(); + if (value < Short.MIN_VALUE || value > Short.MAX_VALUE) { + raiseOverflowException(number, targetClass); + } + return new Short(number.shortValue()); + } + else if (targetClass.equals(Integer.class)) { + long value = number.longValue(); + if (value < Integer.MIN_VALUE || value > Integer.MAX_VALUE) { + raiseOverflowException(number, targetClass); + } + return new Integer(number.intValue()); + } + else if (targetClass.equals(Long.class)) { + return new Long(number.longValue()); + } + else if (targetClass.equals(BigInteger.class)) { + if (number instanceof BigDecimal) { + // do not lose precision - use BigDecimal's own conversion + return ((BigDecimal) number).toBigInteger(); + } + else { + // original value is not a Big* number - use standard long conversion + return BigInteger.valueOf(number.longValue()); + } + } + else if (targetClass.equals(Float.class)) { + return new Float(number.floatValue()); + } + else if (targetClass.equals(Double.class)) { + return new Double(number.doubleValue()); + } + else if (targetClass.equals(BigDecimal.class)) { + // always use BigDecimal(String) here to avoid unpredictability of BigDecimal(double) + // (see BigDecimal javadoc for details) + return new BigDecimal(number.toString()); + } + else { + throw new IllegalArgumentException("Could not convert number [" + number + "] of type [" + + number.getClass().getName() + "] to unknown target class [" + targetClass.getName() + "]"); + } + } + + /** + * Raise an overflow exception for the given number and target class. + * @param number the number we tried to convert + * @param targetClass the target class we tried to convert to + */ + private static void raiseOverflowException(Number number, Class targetClass) { + throw new IllegalArgumentException("Could not convert number [" + number + "] of type [" + + number.getClass().getName() + "] to target class [" + targetClass.getName() + "]: overflow"); + } + + /** + * Parse the given text into a number instance of the given target class, + * using the corresponding decode / valueOf methods. + *

Trims the input String before attempting to parse the number. + * Supports numbers in hex format (with leading "0x", "0X" or "#") as well. + * @param text the text to convert + * @param targetClass the target class to parse into + * @return the parsed number + * @throws IllegalArgumentException if the target class is not supported + * (i.e. not a standard Number subclass as included in the JDK) + * @see java.lang.Byte#decode + * @see java.lang.Short#decode + * @see java.lang.Integer#decode + * @see java.lang.Long#decode + * @see #decodeBigInteger(String) + * @see java.lang.Float#valueOf + * @see java.lang.Double#valueOf + * @see java.math.BigDecimal#BigDecimal(String) + */ + public static Number parseNumber(String text, Class targetClass) { + Assert.notNull(text, "Text must not be null"); + Assert.notNull(targetClass, "Target class must not be null"); + String trimmed = StringUtils.trimAllWhitespace(text); + + if (targetClass.equals(Byte.class)) { + return (isHexNumber(trimmed) ? Byte.decode(trimmed) : Byte.valueOf(trimmed)); + } + else if (targetClass.equals(Short.class)) { + return (isHexNumber(trimmed) ? Short.decode(trimmed) : Short.valueOf(trimmed)); + } + else if (targetClass.equals(Integer.class)) { + return (isHexNumber(trimmed) ? Integer.decode(trimmed) : Integer.valueOf(trimmed)); + } + else if (targetClass.equals(Long.class)) { + return (isHexNumber(trimmed) ? Long.decode(trimmed) : Long.valueOf(trimmed)); + } + else if (targetClass.equals(BigInteger.class)) { + return (isHexNumber(trimmed) ? decodeBigInteger(trimmed) : new BigInteger(trimmed)); + } + else if (targetClass.equals(Float.class)) { + return Float.valueOf(trimmed); + } + else if (targetClass.equals(Double.class)) { + return Double.valueOf(trimmed); + } + else if (targetClass.equals(BigDecimal.class) || targetClass.equals(Number.class)) { + return new BigDecimal(trimmed); + } + else { + throw new IllegalArgumentException( + "Cannot convert String [" + text + "] to target class [" + targetClass.getName() + "]"); + } + } + + /** + * Parse the given text into a number instance of the given target class, + * using the given NumberFormat. Trims the input String + * before attempting to parse the number. + * @param text the text to convert + * @param targetClass the target class to parse into + * @param numberFormat the NumberFormat to use for parsing (if null, + * this method falls back to parseNumber(String, Class)) + * @return the parsed number + * @throws IllegalArgumentException if the target class is not supported + * (i.e. not a standard Number subclass as included in the JDK) + * @see java.text.NumberFormat#parse + * @see #convertNumberToTargetClass + * @see #parseNumber(String, Class) + */ + public static Number parseNumber(String text, Class targetClass, NumberFormat numberFormat) { + if (numberFormat != null) { + Assert.notNull(text, "Text must not be null"); + Assert.notNull(targetClass, "Target class must not be null"); + DecimalFormat decimalFormat = null; + boolean resetBigDecimal = false; + if (numberFormat instanceof DecimalFormat) { + decimalFormat = (DecimalFormat) numberFormat; + if (BigDecimal.class.equals(targetClass) && decimalFormatSupportsBigDecimal && + !decimalFormat.isParseBigDecimal()) { + decimalFormat.setParseBigDecimal(true); + resetBigDecimal = true; + } + } + try { + Number number = numberFormat.parse(StringUtils.trimAllWhitespace(text)); + return convertNumberToTargetClass(number, targetClass); + } + catch (ParseException ex) { + IllegalArgumentException iae = + new IllegalArgumentException("Could not parse number: " + ex.getMessage()); + iae.initCause(ex); + throw iae; + } + finally { + if (resetBigDecimal) { + decimalFormat.setParseBigDecimal(false); + } + } + } + else { + return parseNumber(text, targetClass); + } + } + + /** + * Determine whether the given value String indicates a hex number, i.e. needs to be + * passed into Integer.decode instead of Integer.valueOf (etc). + */ + private static boolean isHexNumber(String value) { + int index = (value.startsWith("-") ? 1 : 0); + return (value.startsWith("0x", index) || value.startsWith("0X", index) || value.startsWith("#", index)); + } + + /** + * Decode a {@link java.math.BigInteger} from a {@link String} value. + * Supports decimal, hex and octal notation. + * @see BigInteger#BigInteger(String, int) + */ + private static BigInteger decodeBigInteger(String value) { + int radix = 10; + int index = 0; + boolean negative = false; + + // Handle minus sign, if present. + if (value.startsWith("-")) { + negative = true; + index++; + } + + // Handle radix specifier, if present. + if (value.startsWith("0x", index) || value.startsWith("0X", index)) { + index += 2; + radix = 16; + } + else if (value.startsWith("#", index)) { + index++; + radix = 16; + } + else if (value.startsWith("0", index) && value.length() > 1 + index) { + index++; + radix = 8; + } + + BigInteger result = new BigInteger(value.substring(index), radix); + return (negative ? result.negate() : result); + } + +} Index: 3rdParty_sources/spring/org/springframework/util/ObjectUtils.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/util/ObjectUtils.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/util/ObjectUtils.java 17 Aug 2012 15:16:10 -0000 1.1 @@ -0,0 +1,833 @@ +/* + * 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.util; + +import java.lang.reflect.Array; +import java.util.Arrays; + +/** + * Miscellaneous object utility methods. Mainly for internal use within the + * framework; consider Jakarta's Commons Lang for a more comprehensive suite + * of object utilities. + * + * @author Juergen Hoeller + * @author Keith Donald + * @author Rod Johnson + * @author Rob Harrop + * @author Alex Ruiz + * @since 19.03.2004 + * @see org.apache.commons.lang.ObjectUtils + */ +public abstract class ObjectUtils { + + private static final int INITIAL_HASH = 7; + private static final int MULTIPLIER = 31; + + private static final String EMPTY_STRING = ""; + private static final String NULL_STRING = "null"; + private static final String ARRAY_START = "{"; + private static final String ARRAY_END = "}"; + private static final String EMPTY_ARRAY = ARRAY_START + ARRAY_END; + private static final String ARRAY_ELEMENT_SEPARATOR = ", "; + + + /** + * Return whether the given throwable is a checked exception: + * that is, neither a RuntimeException nor an Error. + * @param ex the throwable to check + * @return whether the throwable is a checked exception + * @see java.lang.Exception + * @see java.lang.RuntimeException + * @see java.lang.Error + */ + public static boolean isCheckedException(Throwable ex) { + return !(ex instanceof RuntimeException || ex instanceof Error); + } + + /** + * Check whether the given exception is compatible with the exceptions + * declared in a throws clause. + * @param ex the exception to checked + * @param declaredExceptions the exceptions declared in the throws clause + * @return whether the given exception is compatible + */ + public static boolean isCompatibleWithThrowsClause(Throwable ex, Class[] declaredExceptions) { + if (!isCheckedException(ex)) { + return true; + } + if (declaredExceptions != null) { + for (int i = 0; i < declaredExceptions.length; i++) { + if (declaredExceptions[i].isAssignableFrom(ex.getClass())) { + return true; + } + } + } + return false; + } + + /** + * Return whether the given array is empty: that is, null + * or of zero length. + * @param array the array to check + * @return whether the given array is empty + */ + public static boolean isEmpty(Object[] array) { + return (array == null || array.length == 0); + } + + /** + * Check whether the given array contains the given element. + * @param array the array to check (may be null, + * in which case the return value will always be false) + * @param element the element to check for + * @return whether the element has been found in the given array + */ + public static boolean containsElement(Object[] array, Object element) { + if (array == null) { + return false; + } + for (int i = 0; i < array.length; i++) { + if (nullSafeEquals(array[i], element)) { + return true; + } + } + return false; + } + + /** + * Append the given Object to the given array, returning a new array + * consisting of the input array contents plus the given Object. + * @param array the array to append to (can be null) + * @param obj the Object to append + * @return the new array (of the same component type; never null) + */ + public static Object[] addObjectToArray(Object[] array, Object obj) { + Class compType = Object.class; + if (array != null) { + compType = array.getClass().getComponentType(); + } + else if (obj != null) { + compType = obj.getClass(); + } + int newArrLength = (array != null ? array.length + 1 : 1); + Object[] newArr = (Object[]) Array.newInstance(compType, newArrLength); + if (array != null) { + System.arraycopy(array, 0, newArr, 0, array.length); + } + newArr[newArr.length - 1] = obj; + return newArr; + } + + /** + * Convert the given array (which may be a primitive array) to an + * object array (if necessary of primitive wrapper objects). + *

A null source value will be converted to an + * empty Object array. + * @param source the (potentially primitive) array + * @return the corresponding object array (never null) + * @throws IllegalArgumentException if the parameter is not an array + */ + public static Object[] toObjectArray(Object source) { + if (source instanceof Object[]) { + return (Object[]) source; + } + if (source == null) { + return new Object[0]; + } + if (!source.getClass().isArray()) { + throw new IllegalArgumentException("Source is not an array: " + source); + } + int length = Array.getLength(source); + if (length == 0) { + return new Object[0]; + } + Class wrapperType = Array.get(source, 0).getClass(); + Object[] newArray = (Object[]) Array.newInstance(wrapperType, length); + for (int i = 0; i < length; i++) { + newArray[i] = Array.get(source, i); + } + return newArray; + } + + + //--------------------------------------------------------------------- + // Convenience methods for content-based equality/hash-code handling + //--------------------------------------------------------------------- + + /** + * Determine if the given objects are equal, returning true + * if both are null or false if only one is + * null. + *

Compares arrays with Arrays.equals, performing an equality + * check based on the array elements rather than the array reference. + * @param o1 first Object to compare + * @param o2 second Object to compare + * @return whether the given objects are equal + * @see java.util.Arrays#equals + */ + public static boolean nullSafeEquals(Object o1, Object o2) { + if (o1 == o2) { + return true; + } + if (o1 == null || o2 == null) { + return false; + } + if (o1.equals(o2)) { + return true; + } + if (o1.getClass().isArray() && o2.getClass().isArray()) { + if (o1 instanceof Object[] && o2 instanceof Object[]) { + return Arrays.equals((Object[]) o1, (Object[]) o2); + } + if (o1 instanceof boolean[] && o2 instanceof boolean[]) { + return Arrays.equals((boolean[]) o1, (boolean[]) o2); + } + if (o1 instanceof byte[] && o2 instanceof byte[]) { + return Arrays.equals((byte[]) o1, (byte[]) o2); + } + if (o1 instanceof char[] && o2 instanceof char[]) { + return Arrays.equals((char[]) o1, (char[]) o2); + } + if (o1 instanceof double[] && o2 instanceof double[]) { + return Arrays.equals((double[]) o1, (double[]) o2); + } + if (o1 instanceof float[] && o2 instanceof float[]) { + return Arrays.equals((float[]) o1, (float[]) o2); + } + if (o1 instanceof int[] && o2 instanceof int[]) { + return Arrays.equals((int[]) o1, (int[]) o2); + } + if (o1 instanceof long[] && o2 instanceof long[]) { + return Arrays.equals((long[]) o1, (long[]) o2); + } + if (o1 instanceof short[] && o2 instanceof short[]) { + return Arrays.equals((short[]) o1, (short[]) o2); + } + } + return false; + } + + /** + * Return as hash code for the given object; typically the value of + * {@link Object#hashCode()}. If the object is an array, + * this method will delegate to any of the nullSafeHashCode + * methods for arrays in this class. If the object is null, + * this method returns 0. + * @see #nullSafeHashCode(Object[]) + * @see #nullSafeHashCode(boolean[]) + * @see #nullSafeHashCode(byte[]) + * @see #nullSafeHashCode(char[]) + * @see #nullSafeHashCode(double[]) + * @see #nullSafeHashCode(float[]) + * @see #nullSafeHashCode(int[]) + * @see #nullSafeHashCode(long[]) + * @see #nullSafeHashCode(short[]) + */ + public static int nullSafeHashCode(Object obj) { + if (obj == null) { + return 0; + } + if (obj.getClass().isArray()) { + if (obj instanceof Object[]) { + return nullSafeHashCode((Object[]) obj); + } + if (obj instanceof boolean[]) { + return nullSafeHashCode((boolean[]) obj); + } + if (obj instanceof byte[]) { + return nullSafeHashCode((byte[]) obj); + } + if (obj instanceof char[]) { + return nullSafeHashCode((char[]) obj); + } + if (obj instanceof double[]) { + return nullSafeHashCode((double[]) obj); + } + if (obj instanceof float[]) { + return nullSafeHashCode((float[]) obj); + } + if (obj instanceof int[]) { + return nullSafeHashCode((int[]) obj); + } + if (obj instanceof long[]) { + return nullSafeHashCode((long[]) obj); + } + if (obj instanceof short[]) { + return nullSafeHashCode((short[]) obj); + } + } + return obj.hashCode(); + } + + /** + * Return a hash code based on the contents of the specified array. + * If array is null, this method returns 0. + */ + public static int nullSafeHashCode(Object[] array) { + if (array == null) { + return 0; + } + int hash = INITIAL_HASH; + int arraySize = array.length; + for (int i = 0; i < arraySize; i++) { + hash = MULTIPLIER * hash + nullSafeHashCode(array[i]); + } + return hash; + } + + /** + * Return a hash code based on the contents of the specified array. + * If array is null, this method returns 0. + */ + public static int nullSafeHashCode(boolean[] array) { + if (array == null) { + return 0; + } + int hash = INITIAL_HASH; + int arraySize = array.length; + for (int i = 0; i < arraySize; i++) { + hash = MULTIPLIER * hash + hashCode(array[i]); + } + return hash; + } + + /** + * Return a hash code based on the contents of the specified array. + * If array is null, this method returns 0. + */ + public static int nullSafeHashCode(byte[] array) { + if (array == null) { + return 0; + } + int hash = INITIAL_HASH; + int arraySize = array.length; + for (int i = 0; i < arraySize; i++) { + hash = MULTIPLIER * hash + array[i]; + } + return hash; + } + + /** + * Return a hash code based on the contents of the specified array. + * If array is null, this method returns 0. + */ + public static int nullSafeHashCode(char[] array) { + if (array == null) { + return 0; + } + int hash = INITIAL_HASH; + int arraySize = array.length; + for (int i = 0; i < arraySize; i++) { + hash = MULTIPLIER * hash + array[i]; + } + return hash; + } + + /** + * Return a hash code based on the contents of the specified array. + * If array is null, this method returns 0. + */ + public static int nullSafeHashCode(double[] array) { + if (array == null) { + return 0; + } + int hash = INITIAL_HASH; + int arraySize = array.length; + for (int i = 0; i < arraySize; i++) { + hash = MULTIPLIER * hash + hashCode(array[i]); + } + return hash; + } + + /** + * Return a hash code based on the contents of the specified array. + * If array is null, this method returns 0. + */ + public static int nullSafeHashCode(float[] array) { + if (array == null) { + return 0; + } + int hash = INITIAL_HASH; + int arraySize = array.length; + for (int i = 0; i < arraySize; i++) { + hash = MULTIPLIER * hash + hashCode(array[i]); + } + return hash; + } + + /** + * Return a hash code based on the contents of the specified array. + * If array is null, this method returns 0. + */ + public static int nullSafeHashCode(int[] array) { + if (array == null) { + return 0; + } + int hash = INITIAL_HASH; + int arraySize = array.length; + for (int i = 0; i < arraySize; i++) { + hash = MULTIPLIER * hash + array[i]; + } + return hash; + } + + /** + * Return a hash code based on the contents of the specified array. + * If array is null, this method returns 0. + */ + public static int nullSafeHashCode(long[] array) { + if (array == null) { + return 0; + } + int hash = INITIAL_HASH; + int arraySize = array.length; + for (int i = 0; i < arraySize; i++) { + hash = MULTIPLIER * hash + hashCode(array[i]); + } + return hash; + } + + /** + * Return a hash code based on the contents of the specified array. + * If array is null, this method returns 0. + */ + public static int nullSafeHashCode(short[] array) { + if (array == null) { + return 0; + } + int hash = INITIAL_HASH; + int arraySize = array.length; + for (int i = 0; i < arraySize; i++) { + hash = MULTIPLIER * hash + array[i]; + } + return hash; + } + + /** + * Return the same value as {@link Boolean#hashCode()}. + * @see Boolean#hashCode() + */ + public static int hashCode(boolean bool) { + return bool ? 1231 : 1237; + } + + /** + * Return the same value as {@link Double#hashCode()}. + * @see Double#hashCode() + */ + public static int hashCode(double dbl) { + long bits = Double.doubleToLongBits(dbl); + return hashCode(bits); + } + + /** + * Return the same value as {@link Float#hashCode()}. + * @see Float#hashCode() + */ + public static int hashCode(float flt) { + return Float.floatToIntBits(flt); + } + + /** + * Return the same value as {@link Long#hashCode()}. + * @see Long#hashCode() + */ + public static int hashCode(long lng) { + return (int) (lng ^ (lng >>> 32)); + } + + + //--------------------------------------------------------------------- + // Convenience methods for toString output + //--------------------------------------------------------------------- + + /** + * Return a String representation of an object's overall identity. + * @param obj the object (may be null) + * @return the object's identity as String representation, + * or an empty String if the object was null + */ + public static String identityToString(Object obj) { + if (obj == null) { + return EMPTY_STRING; + } + return obj.getClass().getName() + "@" + getIdentityHexString(obj); + } + + /** + * Return a hex String form of an object's identity hash code. + * @param obj the object + * @return the object's identity code in hex notation + */ + public static String getIdentityHexString(Object obj) { + return Integer.toHexString(System.identityHashCode(obj)); + } + + /** + * Return a content-based String representation if obj is + * not null; otherwise returns an empty String. + *

Differs from {@link #nullSafeToString(Object)} in that it returns + * an empty String rather than "null" for a null value. + * @param obj the object to build a display String for + * @return a display String representation of obj + * @see #nullSafeToString(Object) + */ + public static String getDisplayString(Object obj) { + if (obj == null) { + return EMPTY_STRING; + } + return nullSafeToString(obj); + } + + /** + * Determine the class name for the given object. + *

Returns "null" if obj is null. + * @param obj the object to introspect (may be null) + * @return the corresponding class name + */ + public static String nullSafeClassName(Object obj) { + return (obj != null ? obj.getClass().getName() : NULL_STRING); + } + + /** + * Return a String representation of the specified Object. + *

Builds a String representation of the contents in case of an array. + * Returns "null" if obj is null. + * @param obj the object to build a String representation for + * @return a String representation of obj + */ + public static String nullSafeToString(Object obj) { + if (obj == null) { + return NULL_STRING; + } + if (obj instanceof String) { + return (String) obj; + } + if (obj instanceof Object[]) { + return nullSafeToString((Object[]) obj); + } + if (obj instanceof boolean[]) { + return nullSafeToString((boolean[]) obj); + } + if (obj instanceof byte[]) { + return nullSafeToString((byte[]) obj); + } + if (obj instanceof char[]) { + return nullSafeToString((char[]) obj); + } + if (obj instanceof double[]) { + return nullSafeToString((double[]) obj); + } + if (obj instanceof float[]) { + return nullSafeToString((float[]) obj); + } + if (obj instanceof int[]) { + return nullSafeToString((int[]) obj); + } + if (obj instanceof long[]) { + return nullSafeToString((long[]) obj); + } + if (obj instanceof short[]) { + return nullSafeToString((short[]) obj); + } + String str = obj.toString(); + return (str != null ? str : EMPTY_STRING); + } + + /** + * Return a String representation of the contents of the specified array. + *

The String representation consists of a list of the array's elements, + * enclosed in curly braces ("{}"). Adjacent elements are separated + * by the characters ", " (a comma followed by a space). Returns + * "null" if array is null. + * @param array the array to build a String representation for + * @return a String representation of array + */ + public static String nullSafeToString(Object[] array) { + if (array == null) { + return NULL_STRING; + } + int length = array.length; + if (length == 0) { + return EMPTY_ARRAY; + } + StringBuffer buffer = new StringBuffer(); + for (int i = 0; i < length; i++) { + if (i == 0) { + buffer.append(ARRAY_START); + } + else { + buffer.append(ARRAY_ELEMENT_SEPARATOR); + } + buffer.append(String.valueOf(array[i])); + } + buffer.append(ARRAY_END); + return buffer.toString(); + } + + /** + * Return a String representation of the contents of the specified array. + *

The String representation consists of a list of the array's elements, + * enclosed in curly braces ("{}"). Adjacent elements are separated + * by the characters ", " (a comma followed by a space). Returns + * "null" if array is null. + * @param array the array to build a String representation for + * @return a String representation of array + */ + public static String nullSafeToString(boolean[] array) { + if (array == null) { + return NULL_STRING; + } + int length = array.length; + if (length == 0) { + return EMPTY_ARRAY; + } + StringBuffer buffer = new StringBuffer(); + for (int i = 0; i < length; i++) { + if (i == 0) { + buffer.append(ARRAY_START); + } + else { + buffer.append(ARRAY_ELEMENT_SEPARATOR); + } + + buffer.append(array[i]); + } + buffer.append(ARRAY_END); + return buffer.toString(); + } + + /** + * Return a String representation of the contents of the specified array. + *

The String representation consists of a list of the array's elements, + * enclosed in curly braces ("{}"). Adjacent elements are separated + * by the characters ", " (a comma followed by a space). Returns + * "null" if array is null. + * @param array the array to build a String representation for + * @return a String representation of array + */ + public static String nullSafeToString(byte[] array) { + if (array == null) { + return NULL_STRING; + } + int length = array.length; + if (length == 0) { + return EMPTY_ARRAY; + } + StringBuffer buffer = new StringBuffer(); + for (int i = 0; i < length; i++) { + if (i == 0) { + buffer.append(ARRAY_START); + } + else { + buffer.append(ARRAY_ELEMENT_SEPARATOR); + } + buffer.append(array[i]); + } + buffer.append(ARRAY_END); + return buffer.toString(); + } + + /** + * Return a String representation of the contents of the specified array. + *

The String representation consists of a list of the array's elements, + * enclosed in curly braces ("{}"). Adjacent elements are separated + * by the characters ", " (a comma followed by a space). Returns + * "null" if array is null. + * @param array the array to build a String representation for + * @return a String representation of array + */ + public static String nullSafeToString(char[] array) { + if (array == null) { + return NULL_STRING; + } + int length = array.length; + if (length == 0) { + return EMPTY_ARRAY; + } + StringBuffer buffer = new StringBuffer(); + for (int i = 0; i < length; i++) { + if (i == 0) { + buffer.append(ARRAY_START); + } + else { + buffer.append(ARRAY_ELEMENT_SEPARATOR); + } + buffer.append("'").append(array[i]).append("'"); + } + buffer.append(ARRAY_END); + return buffer.toString(); + } + + /** + * Return a String representation of the contents of the specified array. + *

The String representation consists of a list of the array's elements, + * enclosed in curly braces ("{}"). Adjacent elements are separated + * by the characters ", " (a comma followed by a space). Returns + * "null" if array is null. + * @param array the array to build a String representation for + * @return a String representation of array + */ + public static String nullSafeToString(double[] array) { + if (array == null) { + return NULL_STRING; + } + int length = array.length; + if (length == 0) { + return EMPTY_ARRAY; + } + StringBuffer buffer = new StringBuffer(); + for (int i = 0; i < length; i++) { + if (i == 0) { + buffer.append(ARRAY_START); + } + else { + buffer.append(ARRAY_ELEMENT_SEPARATOR); + } + + buffer.append(array[i]); + } + buffer.append(ARRAY_END); + return buffer.toString(); + } + + /** + * Return a String representation of the contents of the specified array. + *

The String representation consists of a list of the array's elements, + * enclosed in curly braces ("{}"). Adjacent elements are separated + * by the characters ", " (a comma followed by a space). Returns + * "null" if array is null. + * @param array the array to build a String representation for + * @return a String representation of array + */ + public static String nullSafeToString(float[] array) { + if (array == null) { + return NULL_STRING; + } + int length = array.length; + if (length == 0) { + return EMPTY_ARRAY; + } + StringBuffer buffer = new StringBuffer(); + for (int i = 0; i < length; i++) { + if (i == 0) { + buffer.append(ARRAY_START); + } + else { + buffer.append(ARRAY_ELEMENT_SEPARATOR); + } + + buffer.append(array[i]); + } + buffer.append(ARRAY_END); + return buffer.toString(); + } + + /** + * Return a String representation of the contents of the specified array. + *

The String representation consists of a list of the array's elements, + * enclosed in curly braces ("{}"). Adjacent elements are separated + * by the characters ", " (a comma followed by a space). Returns + * "null" if array is null. + * @param array the array to build a String representation for + * @return a String representation of array + */ + public static String nullSafeToString(int[] array) { + if (array == null) { + return NULL_STRING; + } + int length = array.length; + if (length == 0) { + return EMPTY_ARRAY; + } + StringBuffer buffer = new StringBuffer(); + for (int i = 0; i < length; i++) { + if (i == 0) { + buffer.append(ARRAY_START); + } + else { + buffer.append(ARRAY_ELEMENT_SEPARATOR); + } + buffer.append(array[i]); + } + buffer.append(ARRAY_END); + return buffer.toString(); + } + + /** + * Return a String representation of the contents of the specified array. + *

The String representation consists of a list of the array's elements, + * enclosed in curly braces ("{}"). Adjacent elements are separated + * by the characters ", " (a comma followed by a space). Returns + * "null" if array is null. + * @param array the array to build a String representation for + * @return a String representation of array + */ + public static String nullSafeToString(long[] array) { + if (array == null) { + return NULL_STRING; + } + int length = array.length; + if (length == 0) { + return EMPTY_ARRAY; + } + StringBuffer buffer = new StringBuffer(); + for (int i = 0; i < length; i++) { + if (i == 0) { + buffer.append(ARRAY_START); + } + else { + buffer.append(ARRAY_ELEMENT_SEPARATOR); + } + buffer.append(array[i]); + } + buffer.append(ARRAY_END); + return buffer.toString(); + } + + /** + * Return a String representation of the contents of the specified array. + *

The String representation consists of a list of the array's elements, + * enclosed in curly braces ("{}"). Adjacent elements are separated + * by the characters ", " (a comma followed by a space). Returns + * "null" if array is null. + * @param array the array to build a String representation for + * @return a String representation of array + */ + public static String nullSafeToString(short[] array) { + if (array == null) { + return NULL_STRING; + } + int length = array.length; + if (length == 0) { + return EMPTY_ARRAY; + } + StringBuffer buffer = new StringBuffer(); + for (int i = 0; i < length; i++) { + if (i == 0) { + buffer.append(ARRAY_START); + } + else { + buffer.append(ARRAY_ELEMENT_SEPARATOR); + } + buffer.append(array[i]); + } + buffer.append(ARRAY_END); + return buffer.toString(); + } + +} Index: 3rdParty_sources/spring/org/springframework/util/PathMatcher.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/util/PathMatcher.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/util/PathMatcher.java 17 Aug 2012 15:16:11 -0000 1.1 @@ -0,0 +1,91 @@ +/* + * 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.util; + +/** + * Strategy interface for String-based path matching. + * + *

Used by {@link org.springframework.core.io.support.PathMatchingResourcePatternResolver}, + * {@link org.springframework.web.servlet.handler.AbstractUrlHandlerMapping}, + * {@link org.springframework.web.servlet.mvc.multiaction.PropertiesMethodNameResolver}, + * and {@link org.springframework.web.servlet.mvc.WebContentInterceptor}. + * + *

The default implementation is {@link AntPathMatcher}, supporting the + * Ant-style pattern syntax. + * + * @author Juergen Hoeller + * @since 1.2 + * @see AntPathMatcher + */ +public interface PathMatcher { + + /** + * Does the given path represent a pattern that can be matched + * by an implementation of this interface? + *

If the return value is false, then the {@link #match} + * method does not have to be used because direct equality comparisons + * on the static path Strings will lead to the same result. + * @param path the path String to check + * @return true if the given path represents a pattern + */ + boolean isPattern(String path); + + /** + * Match the given path against the given pattern, + * according to this PathMatcher's matching strategy. + * @param pattern the pattern to match against + * @param path the path String to test + * @return true if the supplied path matched, + * false if it didn't + */ + boolean match(String pattern, String path); + + /** + * Match the given path against the corresponding part of the given + * pattern, according to this PathMatcher's matching strategy. + *

Determines whether the pattern at least matches as far as the given base + * path goes, assuming that a full path may then match as well. + * @param pattern the pattern to match against + * @param path the path String to test + * @return true if the supplied path matched, + * false if it didn't + */ + boolean matchStart(String pattern, String path); + + /** + * Given a pattern and a full path, determine the pattern-mapped part. + *

This method is supposed to find out which part of the path is matched + * dynamically through an actual pattern, that is, it strips off a statically + * defined leading path from the given full path, returning only the actually + * pattern-matched part of the path. + *

For example: For "myroot/*.html" as pattern and "myroot/myfile.html" + * as full path, this method should return "myfile.html". The detailed + * determination rules are specified to this PathMatcher's matching strategy. + *

A simple implementation may return the given full path as-is in case + * of an actual pattern, and the empty String in case of the pattern not + * containing any dynamic parts (i.e. the pattern parameter being + * a static path that wouldn't qualify as an actual {@link #isPattern pattern}). + * A sophisticated implementation will differentiate between the static parts + * and the dynamic parts of the given path pattern. + * @param pattern the path pattern + * @param path the full path to introspect + * @return the pattern-mapped part of the given path + * (never null) + */ + String extractPathWithinPattern(String pattern, String path); + +} Index: 3rdParty_sources/spring/org/springframework/util/PatternMatchUtils.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/util/PatternMatchUtils.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/util/PatternMatchUtils.java 17 Aug 2012 15:16:10 -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.util; + +/** + * Utility methods for simple pattern matching, in particular for + * Spring's typical "xxx*", "*xxx" and "*xxx*" pattern styles. + * + * @author Juergen Hoeller + * @since 2.0 + */ +public abstract class PatternMatchUtils { + + /** + * Match a String against the given pattern, supporting the following simple + * pattern styles: "xxx*", "*xxx", "*xxx*" and "xxx*yyy" matches (with an + * arbitrary number of pattern parts), as well as direct equality. + * @param pattern the pattern to match against + * @param str the String to match + * @return whether the String matches the given pattern + */ + public static boolean simpleMatch(String pattern, String str) { + if (pattern == null || str == null) { + return false; + } + int firstIndex = pattern.indexOf('*'); + if (firstIndex == -1) { + return pattern.equals(str); + } + if (firstIndex == 0) { + if (pattern.length() == 1) { + return true; + } + int nextIndex = pattern.indexOf('*', firstIndex + 1); + if (nextIndex == -1) { + return str.endsWith(pattern.substring(1)); + } + String part = pattern.substring(1, nextIndex); + int partIndex = str.indexOf(part); + while (partIndex != -1) { + if (simpleMatch(pattern.substring(nextIndex), str.substring(partIndex + part.length()))) { + return true; + } + partIndex = str.indexOf(part, partIndex + 1); + } + return false; + } + return (str.length() >= firstIndex && + pattern.substring(0, firstIndex).equals(str.substring(0, firstIndex)) && + simpleMatch(pattern.substring(firstIndex), str.substring(firstIndex))); + } + + /** + * Match a String against the given patterns, supporting the following simple + * pattern styles: "xxx*", "*xxx", "*xxx*" and "xxx*yyy" matches (with an + * arbitrary number of pattern parts), as well as direct equality. + * @param patterns the patterns to match against + * @param str the String to match + * @return whether the String matches any of the given patterns + */ + public static boolean simpleMatch(String[] patterns, String str) { + if (patterns != null) { + for (int i = 0; i < patterns.length; i++) { + if (simpleMatch(patterns[i], str)) { + return true; + } + } + } + return false; + } + +} Index: 3rdParty_sources/spring/org/springframework/util/PropertiesPersister.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/util/PropertiesPersister.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/util/PropertiesPersister.java 17 Aug 2012 15:16:10 -0000 1.1 @@ -0,0 +1,121 @@ +/* + * 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.util; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Reader; +import java.io.Writer; +import java.util.Properties; + +/** + * Strategy interface for persisting java.util.Properties, + * allowing for pluggable parsing strategies. + * + *

The default implementation is DefaultPropertiesPersister, + * providing the native parsing of java.util.Properties, + * but allowing for reading from any Reader and writing to any Writer + * (which allows to specify an encoding for a properties file). + * + *

As of Spring 1.2.2, this interface also supports properties XML files, + * through the loadFromXml and storeToXml methods. + * The default implementations delegate to JDK 1.5's corresponding methods. + * + * @author Juergen Hoeller + * @since 10.03.2004 + * @see DefaultPropertiesPersister + * @see java.util.Properties + */ +public interface PropertiesPersister { + + /** + * Load properties from the given InputStream into the given + * Properties object. + * @param props the Properties object to load into + * @param is the InputStream to load from + * @throws IOException in case of I/O errors + * @see java.util.Properties#load + */ + void load(Properties props, InputStream is) throws IOException; + + /** + * Load properties from the given Reader into the given + * Properties object. + * @param props the Properties object to load into + * @param reader the Reader to load from + * @throws IOException in case of I/O errors + */ + void load(Properties props, Reader reader) throws IOException; + + + /** + * Write the contents of the given Properties object to the + * given OutputStream. + * @param props the Properties object to store + * @param os the OutputStream to write to + * @param header the description of the property list + * @throws IOException in case of I/O errors + * @see java.util.Properties#store + */ + void store(Properties props, OutputStream os, String header) throws IOException; + + /** + * Write the contents of the given Properties object to the + * given Writer. + * @param props the Properties object to store + * @param writer the Writer to write to + * @param header the description of the property list + * @throws IOException in case of I/O errors + */ + void store(Properties props, Writer writer, String header) throws IOException; + + + /** + * Load properties from the given XML InputStream into the + * given Properties object. + * @param props the Properties object to load into + * @param is the InputStream to load from + * @throws IOException in case of I/O errors + * @see java.util.Properties#loadFromXML(java.io.InputStream) + */ + void loadFromXml(Properties props, InputStream is) throws IOException; + + /** + * Write the contents of the given Properties object to the + * given XML OutputStream. + * @param props the Properties object to store + * @param os the OutputStream to write to + * @param header the description of the property list + * @throws IOException in case of I/O errors + * @see java.util.Properties#storeToXML(java.io.OutputStream, String) + */ + void storeToXml(Properties props, OutputStream os, String header) throws IOException; + + /** + * Write the contents of the given Properties object to the + * given XML OutputStream. + * @param props the Properties object to store + * @param os the OutputStream to write to + * @param encoding the encoding to use + * @param header the description of the property list + * @throws IOException in case of I/O errors + * @see java.util.Properties#storeToXML(java.io.OutputStream, String, String) + */ + void storeToXml(Properties props, OutputStream os, String header, String encoding) throws IOException; + +} Index: 3rdParty_sources/spring/org/springframework/util/ReflectionUtils.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/util/ReflectionUtils.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/util/ReflectionUtils.java 17 Aug 2012 15:16:10 -0000 1.1 @@ -0,0 +1,624 @@ +/* + * 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.util; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * Simple utility class for working with the reflection API and handling + * reflection exceptions. + * + *

Only intended for internal use. + * + * @author Juergen Hoeller + * @author Rob Harrop + * @author Rod Johnson + * @author Costin Leau + * @author Sam Brannen + * @since 1.2.2 + */ +public abstract class ReflectionUtils { + + /** + * Attempt to find a {@link Field field} on the supplied {@link Class} with + * the supplied name. Searches all superclasses up to {@link Object}. + * @param clazz the class to introspect + * @param name the name of the field + * @return the corresponding Field object, or null if not found + */ + public static Field findField(Class clazz, String name) { + return findField(clazz, name, null); + } + + /** + * Attempt to find a {@link Field field} on the supplied {@link Class} with + * the supplied name and/or {@link Class type}. Searches all + * superclasses up to {@link Object}. + * @param clazz the class to introspect + * @param name the name of the field (may be null if type is specified) + * @param type the type of the field (may be null if name is specified) + * @return the corresponding Field object, or null if not found + */ + public static Field findField(Class clazz, String name, Class type) { + Assert.notNull(clazz, "Class must not be null"); + Assert.isTrue(name != null || type != null, "Either name or type of the field must be specified"); + Class searchType = clazz; + while (!Object.class.equals(searchType) && searchType != null) { + Field[] fields = searchType.getDeclaredFields(); + for (int i = 0; i < fields.length; i++) { + Field field = fields[i]; + if ((name == null || name.equals(field.getName())) + && (type == null || type.equals(field.getType()))) { + return field; + } + } + searchType = searchType.getSuperclass(); + } + return null; + } + + /** + * Set the field represented by the supplied {@link Field field object} on + * the specified {@link Object target object} to the specified + * value. In accordance with + * {@link Field#set(Object, Object)} semantics, the new value is + * automatically unwrapped if the underlying field has a primitive type. + *

Thrown exceptions are handled via a call to + * {@link #handleReflectionException(Exception)}. + * @param field the field to set + * @param target the target object on which to set the field + * @param value the value to set; may be null + */ + public static void setField(Field field, Object target, Object value) { + try { + field.set(target, value); + } + catch (IllegalAccessException ex) { + handleReflectionException(ex); + throw new IllegalStateException( + "Unexpected reflection exception - " + ex.getClass().getName() + ": " + ex.getMessage()); + } + } + + /** + * Get the field represented by the supplied {@link Field field object} on + * the specified {@link Object target object}. In accordance with + * {@link Field#get(Object)} semantics, the returned value is + * automatically wrapped if the underlying field has a primitive type. + *

Thrown exceptions are handled via a call to + * {@link #handleReflectionException(Exception)}. + * @param field the field to get + * @param target the target object from which to get the field + * @return the field's current value + */ + public static Object getField(Field field, Object target) { + try { + return field.get(target); + } + catch (IllegalAccessException ex) { + handleReflectionException(ex); + throw new IllegalStateException( + "Unexpected reflection exception - " + ex.getClass().getName() + ": " + ex.getMessage()); + } + } + + /** + * Attempt to find a {@link Method} on the supplied class with the supplied name + * and no parameters. Searches all superclasses up to Object. + *

Returns null if no {@link Method} can be found. + * @param clazz the class to introspect + * @param name the name of the method + * @return the Method object, or null if none found + */ + public static Method findMethod(Class clazz, String name) { + return findMethod(clazz, name, new Class[0]); + } + + /** + * Attempt to find a {@link Method} on the supplied class with the supplied name + * and parameter types. Searches all superclasses up to Object. + *

Returns null if no {@link Method} can be found. + * @param clazz the class to introspect + * @param name the name of the method + * @param paramTypes the parameter types of the method + * (may be null to indicate any signature) + * @return the Method object, or null if none found + */ + public static Method findMethod(Class clazz, String name, Class[] paramTypes) { + Assert.notNull(clazz, "Class must not be null"); + Assert.notNull(name, "Method name must not be null"); + Class searchType = clazz; + while (!Object.class.equals(searchType) && searchType != null) { + Method[] methods = (searchType.isInterface() ? searchType.getMethods() : searchType.getDeclaredMethods()); + for (int i = 0; i < methods.length; i++) { + Method method = methods[i]; + if (name.equals(method.getName()) && + (paramTypes == null || Arrays.equals(paramTypes, method.getParameterTypes()))) { + return method; + } + } + searchType = searchType.getSuperclass(); + } + return null; + } + + /** + * Invoke the specified {@link Method} against the supplied target object + * with no arguments. The target object can be null when + * invoking a static {@link Method}. + *

Thrown exceptions are handled via a call to {@link #handleReflectionException}. + * @param method the method to invoke + * @param target the target object to invoke the method on + * @return the invocation result, if any + * @see #invokeMethod(java.lang.reflect.Method, Object, Object[]) + */ + public static Object invokeMethod(Method method, Object target) { + return invokeMethod(method, target, null); + } + + /** + * Invoke the specified {@link Method} against the supplied target object + * with the supplied arguments. The target object can be null + * when invoking a static {@link Method}. + *

Thrown exceptions are handled via a call to {@link #handleReflectionException}. + * @param method the method to invoke + * @param target the target object to invoke the method on + * @param args the invocation arguments (may be null) + * @return the invocation result, if any + */ + public static Object invokeMethod(Method method, Object target, Object[] args) { + try { + return method.invoke(target, args); + } + catch (Exception ex) { + handleReflectionException(ex); + } + throw new IllegalStateException("Should never get here"); + } + + /** + * Invoke the specified JDBC API {@link Method} against the supplied + * target object with no arguments. + * @param method the method to invoke + * @param target the target object to invoke the method on + * @return the invocation result, if any + * @throws SQLException the JDBC API SQLException to rethrow (if any) + * @see #invokeJdbcMethod(java.lang.reflect.Method, Object, Object[]) + */ + public static Object invokeJdbcMethod(Method method, Object target) throws SQLException { + return invokeJdbcMethod(method, target, null); + } + + /** + * Invoke the specified JDBC API {@link Method} against the supplied + * target object with the supplied arguments. + * @param method the method to invoke + * @param target the target object to invoke the method on + * @param args the invocation arguments (may be null) + * @return the invocation result, if any + * @throws SQLException the JDBC API SQLException to rethrow (if any) + * @see #invokeMethod(java.lang.reflect.Method, Object, Object[]) + */ + public static Object invokeJdbcMethod(Method method, Object target, Object[] args) throws SQLException { + try { + return method.invoke(target, args); + } + catch (IllegalAccessException ex) { + handleReflectionException(ex); + } + catch (InvocationTargetException ex) { + if (ex.getTargetException() instanceof SQLException) { + throw (SQLException) ex.getTargetException(); + } + handleInvocationTargetException(ex); + } + throw new IllegalStateException("Should never get here"); + } + + /** + * Handle the given reflection exception. Should only be called if + * no checked exception is expected to be thrown by the target method. + *

Throws the underlying RuntimeException or Error in case of an + * InvocationTargetException with such a root cause. Throws an + * IllegalStateException with an appropriate message else. + * @param ex the reflection exception to handle + */ + public static void handleReflectionException(Exception ex) { + if (ex instanceof NoSuchMethodException) { + throw new IllegalStateException("Method not found: " + ex.getMessage()); + } + if (ex instanceof IllegalAccessException) { + throw new IllegalStateException("Could not access method: " + ex.getMessage()); + } + if (ex instanceof InvocationTargetException) { + handleInvocationTargetException((InvocationTargetException) ex); + } + if (ex instanceof RuntimeException) { + throw (RuntimeException) ex; + } + handleUnexpectedException(ex); + } + + /** + * Handle the given invocation target exception. Should only be called if + * no checked exception is expected to be thrown by the target method. + *

Throws the underlying RuntimeException or Error in case of such + * a root cause. Throws an IllegalStateException else. + * @param ex the invocation target exception to handle + */ + public static void handleInvocationTargetException(InvocationTargetException ex) { + rethrowRuntimeException(ex.getTargetException()); + } + + /** + * Rethrow the given {@link Throwable exception}, which is presumably the + * target exception of an {@link InvocationTargetException}. + * Should only be called if no checked exception is expected to be thrown by + * the target method. + *

Rethrows the underlying exception cast to an {@link RuntimeException} + * or {@link Error} if appropriate; otherwise, throws an + * {@link IllegalStateException}. + * @param ex the exception to rethrow + * @throws RuntimeException the rethrown exception + */ + public static void rethrowRuntimeException(Throwable ex) { + if (ex instanceof RuntimeException) { + throw (RuntimeException) ex; + } + if (ex instanceof Error) { + throw (Error) ex; + } + handleUnexpectedException(ex); + } + + /** + * Rethrow the given {@link Throwable exception}, which is presumably the + * target exception of an {@link InvocationTargetException}. + * Should only be called if no checked exception is expected to be thrown by + * the target method. + *

Rethrows the underlying exception cast to an {@link Exception} or + * {@link Error} if appropriate; otherwise, throws an + * {@link IllegalStateException}. + * @param ex the exception to rethrow + * @throws Exception the rethrown exception (in case of a checked exception) + */ + public static void rethrowException(Throwable ex) throws Exception { + if (ex instanceof Exception) { + throw (Exception) ex; + } + if (ex instanceof Error) { + throw (Error) ex; + } + handleUnexpectedException(ex); + } + + /** + * Throws an IllegalStateException with the given exception as root cause. + * @param ex the unexpected exception + */ + private static void handleUnexpectedException(Throwable ex) { + // Needs to avoid the chained constructor for JDK 1.4 compatibility. + IllegalStateException isex = new IllegalStateException("Unexpected exception thrown"); + isex.initCause(ex); + throw isex; + } + + /** + * Determine whether the given method explicitly declares the given exception + * or one of its superclasses, which means that an exception of that type + * can be propagated as-is within a reflective invocation. + * @param method the declaring method + * @param exceptionType the exception to throw + * @return true if the exception can be thrown as-is; + * false if it needs to be wrapped + */ + public static boolean declaresException(Method method, Class exceptionType) { + Assert.notNull(method, "Method must not be null"); + Class[] declaredExceptions = method.getExceptionTypes(); + for (int i = 0; i < declaredExceptions.length; i++) { + Class declaredException = declaredExceptions[i]; + if (declaredException.isAssignableFrom(exceptionType)) { + return true; + } + } + return false; + } + + + /** + * Determine whether the given field is a "public static final" constant. + * @param field the field to check + */ + public static boolean isPublicStaticFinal(Field field) { + int modifiers = field.getModifiers(); + return (Modifier.isPublic(modifiers) && Modifier.isStatic(modifiers) && Modifier.isFinal(modifiers)); + } + + /** + * Determine whether the given method is an "equals" method. + * @see java.lang.Object#equals + */ + public static boolean isEqualsMethod(Method method) { + if (method == null || !method.getName().equals("equals")) { + return false; + } + Class[] paramTypes = method.getParameterTypes(); + return (paramTypes.length == 1 && paramTypes[0] == Object.class); + } + + /** + * Determine whether the given method is a "hashCode" method. + * @see java.lang.Object#hashCode + */ + public static boolean isHashCodeMethod(Method method) { + return (method != null && method.getName().equals("hashCode") && + method.getParameterTypes().length == 0); + } + + /** + * Determine whether the given method is a "toString" method. + * @see java.lang.Object#toString() + */ + public static boolean isToStringMethod(Method method) { + return (method != null && method.getName().equals("toString") && + method.getParameterTypes().length == 0); + } + + + /** + * Make the given field accessible, explicitly setting it accessible if necessary. + * The setAccessible(true) method is only called when actually necessary, + * to avoid unnecessary conflicts with a JVM SecurityManager (if active). + * @param field the field to make accessible + * @see java.lang.reflect.Field#setAccessible + */ + public static void makeAccessible(Field field) { + if (!Modifier.isPublic(field.getModifiers()) || + !Modifier.isPublic(field.getDeclaringClass().getModifiers())) { + field.setAccessible(true); + } + } + + /** + * Make the given method accessible, explicitly setting it accessible if necessary. + * The setAccessible(true) method is only called when actually necessary, + * to avoid unnecessary conflicts with a JVM SecurityManager (if active). + * @param method the method to make accessible + * @see java.lang.reflect.Method#setAccessible + */ + public static void makeAccessible(Method method) { + if (!Modifier.isPublic(method.getModifiers()) || + !Modifier.isPublic(method.getDeclaringClass().getModifiers())) { + method.setAccessible(true); + } + } + + /** + * Make the given constructor accessible, explicitly setting it accessible if necessary. + * The setAccessible(true) method is only called when actually necessary, + * to avoid unnecessary conflicts with a JVM SecurityManager (if active). + * @param ctor the constructor to make accessible + * @see java.lang.reflect.Constructor#setAccessible + */ + public static void makeAccessible(Constructor ctor) { + if (!Modifier.isPublic(ctor.getModifiers()) || + !Modifier.isPublic(ctor.getDeclaringClass().getModifiers())) { + ctor.setAccessible(true); + } + } + + + /** + * Perform the given callback operation on all matching methods of the + * given class and superclasses. + *

The same named method occurring on subclass and superclass will + * appear twice, unless excluded by a {@link MethodFilter}. + * @param targetClass class to start looking at + * @param mc the callback to invoke for each method + * @see #doWithMethods(Class, MethodCallback, MethodFilter) + */ + public static void doWithMethods(Class targetClass, MethodCallback mc) throws IllegalArgumentException { + doWithMethods(targetClass, mc, null); + } + + /** + * Perform the given callback operation on all matching methods of the + * given class and superclasses. + *

The same named method occurring on subclass and superclass will + * appear twice, unless excluded by the specified {@link MethodFilter}. + * @param targetClass class to start looking at + * @param mc the callback to invoke for each method + * @param mf the filter that determines the methods to apply the callback to + */ + public static void doWithMethods(Class targetClass, MethodCallback mc, MethodFilter mf) + throws IllegalArgumentException { + + // Keep backing up the inheritance hierarchy. + do { + Method[] methods = targetClass.getDeclaredMethods(); + for (int i = 0; i < methods.length; i++) { + if (mf != null && !mf.matches(methods[i])) { + continue; + } + try { + mc.doWith(methods[i]); + } + catch (IllegalAccessException ex) { + throw new IllegalStateException( + "Shouldn't be illegal to access method '" + methods[i].getName() + "': " + ex); + } + } + targetClass = targetClass.getSuperclass(); + } + while (targetClass != null); + } + + /** + * Get all declared methods on the leaf class and all superclasses. + * Leaf class methods are included first. + */ + public static Method[] getAllDeclaredMethods(Class leafClass) throws IllegalArgumentException { + final List list = new ArrayList(32); + doWithMethods(leafClass, new MethodCallback() { + public void doWith(Method method) { + list.add(method); + } + }); + return (Method[]) list.toArray(new Method[list.size()]); + } + + + /** + * Invoke the given callback on all fields in the target class, + * going up the class hierarchy to get all declared fields. + * @param targetClass the target class to analyze + * @param fc the callback to invoke for each field + */ + public static void doWithFields(Class targetClass, FieldCallback fc) throws IllegalArgumentException { + doWithFields(targetClass, fc, null); + } + + /** + * Invoke the given callback on all fields in the target class, + * going up the class hierarchy to get all declared fields. + * @param targetClass the target class to analyze + * @param fc the callback to invoke for each field + * @param ff the filter that determines the fields to apply the callback to + */ + public static void doWithFields(Class targetClass, FieldCallback fc, FieldFilter ff) + throws IllegalArgumentException { + + // Keep backing up the inheritance hierarchy. + do { + // Copy each field declared on this class unless it's static or file. + Field[] fields = targetClass.getDeclaredFields(); + for (int i = 0; i < fields.length; i++) { + // Skip static and final fields. + if (ff != null && !ff.matches(fields[i])) { + continue; + } + try { + fc.doWith(fields[i]); + } + catch (IllegalAccessException ex) { + throw new IllegalStateException( + "Shouldn't be illegal to access field '" + fields[i].getName() + "': " + ex); + } + } + targetClass = targetClass.getSuperclass(); + } + while (targetClass != null && targetClass != Object.class); + } + + /** + * Given the source object and the destination, which must be the same class + * or a subclass, copy all fields, including inherited fields. Designed to + * work on objects with public no-arg constructors. + * @throws IllegalArgumentException if the arguments are incompatible + */ + public static void shallowCopyFieldState(final Object src, final Object dest) throws IllegalArgumentException { + if (src == null) { + throw new IllegalArgumentException("Source for field copy cannot be null"); + } + if (dest == null) { + throw new IllegalArgumentException("Destination for field copy cannot be null"); + } + if (!src.getClass().isAssignableFrom(dest.getClass())) { + throw new IllegalArgumentException("Destination class [" + dest.getClass().getName() + + "] must be same or subclass as source class [" + src.getClass().getName() + "]"); + } + doWithFields(src.getClass(), new FieldCallback() { + public void doWith(Field field) throws IllegalArgumentException, IllegalAccessException { + makeAccessible(field); + Object srcValue = field.get(src); + field.set(dest, srcValue); + } + }, COPYABLE_FIELDS); + } + + + /** + * Action to take on each method. + */ + public static interface MethodCallback { + + /** + * Perform an operation using the given method. + * @param method the method to operate on + */ + void doWith(Method method) throws IllegalArgumentException, IllegalAccessException; + } + + + /** + * Callback optionally used to method fields to be operated on by a method callback. + */ + public static interface MethodFilter { + + /** + * Determine whether the given method matches. + * @param method the method to check + */ + boolean matches(Method method); + } + + + /** + * Callback interface invoked on each field in the hierarchy. + */ + public static interface FieldCallback { + + /** + * Perform an operation using the given field. + * @param field the field to operate on + */ + void doWith(Field field) throws IllegalArgumentException, IllegalAccessException; + } + + + /** + * Callback optionally used to filter fields to be operated on by a field callback. + */ + public static interface FieldFilter { + + /** + * Determine whether the given field matches. + * @param field the field to check + */ + boolean matches(Field field); + } + + + /** + * Pre-built FieldFilter that matches all non-static, non-final fields. + */ + public static FieldFilter COPYABLE_FIELDS = new FieldFilter() { + public boolean matches(Field field) { + return !(Modifier.isStatic(field.getModifiers()) || + Modifier.isFinal(field.getModifiers())); + } + }; + +} Index: 3rdParty_sources/spring/org/springframework/util/ResourceUtils.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/util/ResourceUtils.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/util/ResourceUtils.java 17 Aug 2012 15:16:09 -0000 1.1 @@ -0,0 +1,318 @@ +/* + * 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.util; + +import java.io.File; +import java.io.FileNotFoundException; +import java.net.MalformedURLException; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; + +/** + * Utility methods for resolving resource locations to files in the + * file system. Mainly for internal use within the framework. + * + *

Consider using Spring's Resource abstraction in the core package + * for handling all kinds of file resources in a uniform manner. + * {@link org.springframework.core.io.ResourceLoader}'s getResource + * method can resolve any location to a {@link org.springframework.core.io.Resource} + * object, which in turn allows to obtain a java.io.File in the + * file system through its getFile() method. + * + *

The main reason for these utility methods for resource location handling + * is to support {@link Log4jConfigurer}, which must be able to resolve + * resource locations before the logging system has been initialized. + * Spring' Resource abstraction in the core package, on the other hand, + * already expects the logging system to be available. + * + * @author Juergen Hoeller + * @since 1.1.5 + * @see org.springframework.core.io.Resource + * @see org.springframework.core.io.ClassPathResource + * @see org.springframework.core.io.FileSystemResource + * @see org.springframework.core.io.UrlResource + * @see org.springframework.core.io.ResourceLoader + */ +public abstract class ResourceUtils { + + /** Pseudo URL prefix for loading from the class path: "classpath:" */ + public static final String CLASSPATH_URL_PREFIX = "classpath:"; + + /** URL prefix for loading from the file system: "file:" */ + public static final String FILE_URL_PREFIX = "file:"; + + /** URL protocol for a file in the file system: "file" */ + public static final String URL_PROTOCOL_FILE = "file"; + + /** URL protocol for an entry from a jar file: "jar" */ + public static final String URL_PROTOCOL_JAR = "jar"; + + /** URL protocol for an entry from a zip file: "zip" */ + public static final String URL_PROTOCOL_ZIP = "zip"; + + /** URL protocol for an entry from a JBoss jar file: "vfszip" */ + public static final String URL_PROTOCOL_VFSZIP = "vfszip"; + + /** URL protocol for an entry from a WebSphere jar file: "wsjar" */ + public static final String URL_PROTOCOL_WSJAR = "wsjar"; + + /** URL protocol for an entry from an OC4J jar file: "code-source" */ + public static final String URL_PROTOCOL_CODE_SOURCE = "code-source"; + + /** Separator between JAR URL and file path within the JAR */ + public static final String JAR_URL_SEPARATOR = "!/"; + + + /** + * Return whether the given resource location is a URL: + * either a special "classpath" pseudo URL or a standard URL. + * @param resourceLocation the location String to check + * @return whether the location qualifies as a URL + * @see #CLASSPATH_URL_PREFIX + * @see java.net.URL + */ + public static boolean isUrl(String resourceLocation) { + if (resourceLocation == null) { + return false; + } + if (resourceLocation.startsWith(CLASSPATH_URL_PREFIX)) { + return true; + } + try { + new URL(resourceLocation); + return true; + } + catch (MalformedURLException ex) { + return false; + } + } + + /** + * Resolve the given resource location to a java.net.URL. + *

Does not check whether the URL actually exists; simply returns + * the URL that the given location would correspond to. + * @param resourceLocation the resource location to resolve: either a + * "classpath:" pseudo URL, a "file:" URL, or a plain file path + * @return a corresponding URL object + * @throws FileNotFoundException if the resource cannot be resolved to a URL + */ + public static URL getURL(String resourceLocation) throws FileNotFoundException { + Assert.notNull(resourceLocation, "Resource location must not be null"); + if (resourceLocation.startsWith(CLASSPATH_URL_PREFIX)) { + String path = resourceLocation.substring(CLASSPATH_URL_PREFIX.length()); + URL url = ClassUtils.getDefaultClassLoader().getResource(path); + if (url == null) { + String description = "class path resource [" + path + "]"; + throw new FileNotFoundException( + description + " cannot be resolved to URL because it does not exist"); + } + return url; + } + try { + // try URL + return new URL(resourceLocation); + } + catch (MalformedURLException ex) { + // no URL -> treat as file path + try { + return new File(resourceLocation).toURI().toURL(); + } + catch (MalformedURLException ex2) { + throw new FileNotFoundException("Resource location [" + resourceLocation + + "] is neither a URL not a well-formed file path"); + } + } + } + + /** + * Resolve the given resource location to a java.io.File, + * i.e. to a file in the file system. + *

Does not check whether the fil actually exists; simply returns + * the File that the given location would correspond to. + * @param resourceLocation the resource location to resolve: either a + * "classpath:" pseudo URL, a "file:" URL, or a plain file path + * @return a corresponding File object + * @throws FileNotFoundException if the resource cannot be resolved to + * a file in the file system + */ + public static File getFile(String resourceLocation) throws FileNotFoundException { + Assert.notNull(resourceLocation, "Resource location must not be null"); + if (resourceLocation.startsWith(CLASSPATH_URL_PREFIX)) { + String path = resourceLocation.substring(CLASSPATH_URL_PREFIX.length()); + String description = "class path resource [" + path + "]"; + URL url = ClassUtils.getDefaultClassLoader().getResource(path); + if (url == null) { + throw new FileNotFoundException( + description + " cannot be resolved to absolute file path " + + "because it does not reside in the file system"); + } + return getFile(url, description); + } + try { + // try URL + return getFile(new URL(resourceLocation)); + } + catch (MalformedURLException ex) { + // no URL -> treat as file path + return new File(resourceLocation); + } + } + + /** + * Resolve the given resource URL to a java.io.File, + * i.e. to a file in the file system. + * @param resourceUrl the resource URL to resolve + * @return a corresponding File object + * @throws FileNotFoundException if the URL cannot be resolved to + * a file in the file system + */ + public static File getFile(URL resourceUrl) throws FileNotFoundException { + return getFile(resourceUrl, "URL"); + } + + /** + * Resolve the given resource URL to a java.io.File, + * i.e. to a file in the file system. + * @param resourceUrl the resource URL to resolve + * @param description a description of the original resource that + * the URL was created for (for example, a class path location) + * @return a corresponding File object + * @throws FileNotFoundException if the URL cannot be resolved to + * a file in the file system + */ + public static File getFile(URL resourceUrl, String description) throws FileNotFoundException { + Assert.notNull(resourceUrl, "Resource URL must not be null"); + if (!URL_PROTOCOL_FILE.equals(resourceUrl.getProtocol())) { + throw new FileNotFoundException( + description + " cannot be resolved to absolute file path " + + "because it does not reside in the file system: " + resourceUrl); + } + try { + return new File(toURI(resourceUrl).getSchemeSpecificPart()); + } + catch (URISyntaxException ex) { + // Fallback for URLs that are not valid URIs (should hardly ever happen). + return new File(resourceUrl.getFile()); + } + } + + /** + * Resolve the given resource URI to a java.io.File, + * i.e. to a file in the file system. + * @param resourceUri the resource URI to resolve + * @return a corresponding File object + * @throws FileNotFoundException if the URL cannot be resolved to + * a file in the file system + */ + public static File getFile(URI resourceUri) throws FileNotFoundException { + return getFile(resourceUri, "URI"); + } + + /** + * Resolve the given resource URI to a java.io.File, + * i.e. to a file in the file system. + * @param resourceUri the resource URI to resolve + * @param description a description of the original resource that + * the URI was created for (for example, a class path location) + * @return a corresponding File object + * @throws FileNotFoundException if the URL cannot be resolved to + * a file in the file system + */ + public static File getFile(URI resourceUri, String description) throws FileNotFoundException { + Assert.notNull(resourceUri, "Resource URI must not be null"); + if (!URL_PROTOCOL_FILE.equals(resourceUri.getScheme())) { + throw new FileNotFoundException( + description + " cannot be resolved to absolute file path " + + "because it does not reside in the file system: " + resourceUri); + } + return new File(resourceUri.getSchemeSpecificPart()); + } + + /** + * Determine whether the given URL points to a resource in a jar file, + * that is, has protocol "jar", "zip", "wsjar" or "code-source". + *

"zip" and "wsjar" are used by BEA WebLogic Server and IBM WebSphere, respectively, + * but can be treated like jar files. The same applies to "code-source" URLs on Oracle + * OC4J, provided that the path contains a jar separator. + * @param url the URL to check + * @return whether the URL has been identified as a JAR URL + */ + public static boolean isJarURL(URL url) { + String protocol = url.getProtocol(); + return (URL_PROTOCOL_JAR.equals(protocol) || + URL_PROTOCOL_ZIP.equals(protocol) || + URL_PROTOCOL_VFSZIP.equals(protocol) || + URL_PROTOCOL_WSJAR.equals(protocol) || + (URL_PROTOCOL_CODE_SOURCE.equals(protocol) && url.getPath().indexOf(JAR_URL_SEPARATOR) != -1)); + } + + /** + * Extract the URL for the actual jar file from the given URL + * (which may point to a resource in a jar file or to a jar file itself). + * @param jarUrl the original URL + * @return the URL for the actual jar file + * @throws MalformedURLException if no valid jar file URL could be extracted + */ + public static URL extractJarFileURL(URL jarUrl) throws MalformedURLException { + String urlFile = jarUrl.getFile(); + int separatorIndex = urlFile.indexOf(JAR_URL_SEPARATOR); + if (separatorIndex != -1) { + String jarFile = urlFile.substring(0, separatorIndex); + try { + return new URL(jarFile); + } + catch (MalformedURLException ex) { + // Probably no protocol in original jar URL, like "jar:C:/mypath/myjar.jar". + // This usually indicates that the jar file resides in the file system. + if (!jarFile.startsWith("/")) { + jarFile = "/" + jarFile; + } + return new URL(FILE_URL_PREFIX + jarFile); + } + } + else { + return jarUrl; + } + } + + /** + * Create a URI instance for the given URL, + * replacing spaces with "%20" quotes first. + *

Furthermore, this method works on JDK 1.4 as well, + * in contrast to the URL.toURI() method. + * @param url the URL to convert into a URI instance + * @return the URI instance + * @throws URISyntaxException if the URL wasn't a valid URI + * @see java.net.URL#toURI() + */ + public static URI toURI(URL url) throws URISyntaxException { + return toURI(url.toString()); + } + + /** + * Create a URI instance for the given location String, + * replacing spaces with "%20" quotes first. + * @param location the location String to convert into a URI instance + * @return the URI instance + * @throws URISyntaxException if the location wasn't a valid URI + */ + public static URI toURI(String location) throws URISyntaxException { + return new URI(StringUtils.replace(location, " ", "%20")); + } + +} Index: 3rdParty_sources/spring/org/springframework/util/ResponseTimeMonitor.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/util/ResponseTimeMonitor.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/util/ResponseTimeMonitor.java 17 Aug 2012 15:16:10 -0000 1.1 @@ -0,0 +1,55 @@ +/* + * 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.util; + +/** + * Interface implemented by objects that can provide performance information + * as well as a record of the number of times they are accessed. + * + *

Implementing objects must ensure that implementing this interface + * does not compromise thread safety. However, it may be acceptable + * for slight innaccuracies in reported statistics to result from the + * avoidance of synchronization: performance may be well be more important + * than exact reporting, so long as the errors are not likely to be misleading. + * + * @author Rod Johnson + * @since November 21, 2000 + * @deprecated as of Spring 2.5, to be removed in Spring 3.0 + */ +public interface ResponseTimeMonitor { + + /** + * Return the number of accesses to this resource. + */ + int getAccessCount(); + + /** + * Return the average response time in milliseconds. + */ + int getAverageResponseTimeMillis(); + + /** + * Return the best (quickest) response time in milliseconds. + */ + int getBestResponseTimeMillis(); + + /** + * Return the worst (slowest) response time in milliseconds. + */ + int getWorstResponseTimeMillis(); + +} Index: 3rdParty_sources/spring/org/springframework/util/ResponseTimeMonitorImpl.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/util/ResponseTimeMonitorImpl.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/util/ResponseTimeMonitorImpl.java 17 Aug 2012 15:16:10 -0000 1.1 @@ -0,0 +1,121 @@ +/* + * 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.util; + +import java.util.Date; + +/** + * Default implementation of {@link ResponseTimeMonitor}. + * + * @author Rod Johnson + * @since November 21, 2000 + * @deprecated as of Spring 2.5, to be removed in Spring 3.0 + */ +public class ResponseTimeMonitorImpl implements ResponseTimeMonitor { + + /** The system time at which this object was initialized */ + private final long initedMillis = System.currentTimeMillis(); + + /** The number of operations recorded by this object */ + private volatile int accessCount; + + /** The sum of the response times for all operations */ + private volatile int totalResponseTimeMillis = 0; + + /** The best response time this object has recorded */ + private volatile int bestResponseTimeMillis = Integer.MAX_VALUE; + + /** The worst response time this object has recorded */ + private volatile int worstResponseTimeMillis = Integer.MIN_VALUE; + + + /** + * Return the date when this object was loaded. + */ + public Date getLoadDate() { + return new Date(this.initedMillis); + } + + /** + * Return the number of hits this object has handled. + */ + public int getAccessCount() { + return this.accessCount; + } + + /** + * Return the number of milliseconds since this object was loaded. + */ + public long getUptimeMillis() { + return System.currentTimeMillis() - this.initedMillis; + } + + /** + * Return the average response time achieved by this object. + */ + public int getAverageResponseTimeMillis() { + int count = getAccessCount(); + // avoid division by 0 + return (count != 0 ? this.totalResponseTimeMillis / count : 0); + } + + /** + * Return the best (lowest) response time achieved by this object. + */ + public int getBestResponseTimeMillis() { + return this.bestResponseTimeMillis; + } + + /** + * Return the worst (slowest) response time achieved by this object. + */ + public int getWorstResponseTimeMillis() { + return this.worstResponseTimeMillis; + } + + + /** + * Utility method to record this response time, updating + * the best and worst response times if necessary. + * @param responseTimeMillis the response time of this request + */ + public synchronized void recordResponseTime(long responseTimeMillis) { + ++this.accessCount; + int iResponseTime = (int) responseTimeMillis; + this.totalResponseTimeMillis += iResponseTime; + if (iResponseTime < this.bestResponseTimeMillis) { + this.bestResponseTimeMillis = iResponseTime; + } + if (iResponseTime > this.worstResponseTimeMillis) { + this.worstResponseTimeMillis = iResponseTime; + } + } + + /** + * Return a human-readable string showing the performance + * data recorded by this object. + */ + public synchronized String toString() { + StringBuffer sb = new StringBuffer(); + sb.append("hits=[").append(getAccessCount()).append("]; "); + sb.append("average=[").append(getAverageResponseTimeMillis()).append("ms]; "); + sb.append("best=[").append(getBestResponseTimeMillis()).append("ms]; "); + sb.append("worst=[").append(getWorstResponseTimeMillis()).append("ms]"); + return sb.toString(); + } + +} Index: 3rdParty_sources/spring/org/springframework/util/StopWatch.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/util/StopWatch.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/util/StopWatch.java 17 Aug 2012 15:16:10 -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.util; + +import java.text.NumberFormat; +import java.util.LinkedList; +import java.util.List; + +/** + * Simple stop watch, allowing for timing of a number of tasks, + * exposing total running time and running time for each named task. + * + *

Conceals use of System.currentTimeMillis(), improving the + * readability of application code and reducing the likelihood of calculation errors. + * + *

Note that this object is not designed to be thread-safe and does not + * use synchronization. + * + *

This class is normally used to verify performance during proof-of-concepts + * and in development, rather than as part of production applications. + * + * @author Rod Johnson + * @author Juergen Hoeller + * @since May 2, 2001 + */ +public class StopWatch { + + /** + * Identifier of this stop watch. + * Handy when we have output from multiple stop watches + * and need to distinguish between them in log or console output. + */ + private final String id; + + private boolean keepTaskList = true; + + /** List of TaskInfo objects */ + private final List taskList = new LinkedList(); + + /** Start time of the current task */ + private long startTimeMillis; + + /** Is the stop watch currently running? */ + private boolean running; + + /** Name of the current task */ + private String currentTaskName; + + private TaskInfo lastTaskInfo; + + private int taskCount; + + /** Total running time */ + private long totalTimeMillis; + + + /** + * Construct a new stop watch. Does not start any task. + */ + public StopWatch() { + this.id = ""; + } + + /** + * Construct a new stop watch with the given id. + * Does not start any task. + * @param id identifier for this stop watch. + * Handy when we have output from multiple stop watches + * and need to distinguish between them. + */ + public StopWatch(String id) { + this.id = id; + } + + /** + * Determine whether the TaskInfo array is built over time. Set this to + * "false" when using a StopWatch for millions of intervals, or the task + * info structure will consume excessive memory. Default is "true". + */ + public void setKeepTaskList(boolean keepTaskList) { + this.keepTaskList = keepTaskList; + } + + + /** + * Start an unnamed task. The results are undefined if {@link #stop()} + * or timing methods are called without invoking this method. + * @see #stop() + */ + public void start() throws IllegalStateException { + start(""); + } + + /** + * Start a named task. The results are undefined if {@link #stop()} + * or timing methods are called without invoking this method. + * @param taskName the name of the task to start + * @see #stop() + */ + public void start(String taskName) throws IllegalStateException { + if (this.running) { + throw new IllegalStateException("Can't start StopWatch: it's already running"); + } + this.startTimeMillis = System.currentTimeMillis(); + this.running = true; + this.currentTaskName = taskName; + } + + /** + * Stop the current task. The results are undefined if timing + * methods are called without invoking at least one pair + * {@link #start()} / {@link #stop()} methods. + * @see #start() + */ + public void stop() throws IllegalStateException { + if (!this.running) { + throw new IllegalStateException("Can't stop StopWatch: it's not running"); + } + long lastTime = System.currentTimeMillis() - this.startTimeMillis; + this.totalTimeMillis += lastTime; + this.lastTaskInfo = new TaskInfo(this.currentTaskName, lastTime); + if (this.keepTaskList) { + this.taskList.add(lastTaskInfo); + } + ++this.taskCount; + this.running = false; + this.currentTaskName = null; + } + + /** + * Return whether the stop watch is currently running. + */ + public boolean isRunning() { + return this.running; + } + + + /** + * Return the time taken by the last task. + */ + public long getLastTaskTimeMillis() throws IllegalStateException { + if (this.lastTaskInfo == null) { + throw new IllegalStateException("No tests run: can't get last interval"); + } + return this.lastTaskInfo.getTimeMillis(); + } + + /** + * Return the total time in milliseconds for all tasks. + */ + public long getTotalTimeMillis() { + return totalTimeMillis; + } + + /** + * Return the total time in seconds for all tasks. + */ + public double getTotalTimeSeconds() { + return totalTimeMillis / 1000.0; + } + + /** + * Return the number of tasks timed. + */ + public int getTaskCount() { + return taskCount; + } + + /** + * Return an array of the data for tasks performed. + */ + public TaskInfo[] getTaskInfo() { + if (!this.keepTaskList) { + throw new UnsupportedOperationException("Task info is not being kept!"); + } + return (TaskInfo[]) this.taskList.toArray(new TaskInfo[this.taskList.size()]); + } + + + /** + * Return a short description of the total running time. + */ + public String shortSummary() { + return "StopWatch '" + this.id + "': running time (millis) = " + getTotalTimeMillis(); + } + + /** + * Return a string with a table describing all tasks performed. + * For custom reporting, call getTaskInfo() and use the task info directly. + */ + public String prettyPrint() { + StringBuffer sb = new StringBuffer(shortSummary()); + sb.append('\n'); + if (!this.keepTaskList) { + sb.append("No task info kept"); + } + else { + TaskInfo[] tasks = getTaskInfo(); + sb.append("-----------------------------------------\n"); + sb.append("ms % Task name\n"); + sb.append("-----------------------------------------\n"); + NumberFormat nf = NumberFormat.getNumberInstance(); + nf.setMinimumIntegerDigits(5); + nf.setGroupingUsed(false); + NumberFormat pf = NumberFormat.getPercentInstance(); + pf.setMinimumIntegerDigits(3); + pf.setGroupingUsed(false); + for (int i = 0; i < tasks.length; i++) { + sb.append(nf.format(tasks[i].getTimeMillis()) + " "); + sb.append(pf.format(tasks[i].getTimeSeconds() / getTotalTimeSeconds()) + " "); + sb.append(tasks[i].getTaskName() + "\n"); + } + } + return sb.toString(); + } + + /** + * Return an informative string describing all tasks performed + * For custom reporting, call getTaskInfo() and use the task info directly. + */ + public String toString() { + StringBuffer sb = new StringBuffer(shortSummary()); + if (this.keepTaskList) { + TaskInfo[] tasks = getTaskInfo(); + for (int i = 0; i < tasks.length; i++) { + sb.append("; [" + tasks[i].getTaskName() + "] took " + tasks[i].getTimeMillis()); + long percent = Math.round((100.0 * tasks[i].getTimeSeconds()) / getTotalTimeSeconds()); + sb.append(" = " + percent + "%"); + } + } + else { + sb.append("; no task info kept"); + } + return sb.toString(); + } + + + /** + * Inner class to hold data about one task executed within the stop watch. + */ + public static class TaskInfo { + + private final String taskName; + + private final long timeMillis; + + private TaskInfo(String taskName, long timeMillis) { + this.taskName = taskName; + this.timeMillis = timeMillis; + } + + /** + * Return the name of this task. + */ + public String getTaskName() { + return taskName; + } + + /** + * Return the time in milliseconds this task took. + */ + public long getTimeMillis() { + return timeMillis; + } + + /** + * Return the time in seconds this task took. + */ + public double getTimeSeconds() { + return timeMillis / 1000.0; + } + } + +} Index: 3rdParty_sources/spring/org/springframework/util/StringUtils.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/util/StringUtils.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/util/StringUtils.java 17 Aug 2012 15:16:10 -0000 1.1 @@ -0,0 +1,1113 @@ +/* + * 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.util; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.Enumeration; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Locale; +import java.util.Properties; +import java.util.Set; +import java.util.StringTokenizer; +import java.util.TreeSet; + +/** + * Miscellaneous {@link String} utility methods. + * + *

Mainly for internal use within the framework; consider + * Jakarta's Commons Lang + * for a more comprehensive suite of String utilities. + * + *

This class delivers some simple functionality that should really + * be provided by the core Java String and {@link StringBuffer} + * classes, such as the ability to {@link #replace} all occurrences of a given + * substring in a target string. It also provides easy-to-use methods to convert + * between delimited strings, such as CSV strings, and collections and arrays. + * + * @author Rod Johnson + * @author Juergen Hoeller + * @author Keith Donald + * @author Rob Harrop + * @author Rick Evans + * @since 16 April 2001 + * @see org.apache.commons.lang.StringUtils + */ +public abstract class StringUtils { + + private static final String FOLDER_SEPARATOR = "/"; + + private static final String WINDOWS_FOLDER_SEPARATOR = "\\"; + + private static final String TOP_PATH = ".."; + + private static final String CURRENT_PATH = "."; + + private static final char EXTENSION_SEPARATOR = '.'; + + + //--------------------------------------------------------------------- + // General convenience methods for working with Strings + //--------------------------------------------------------------------- + + /** + * Check that the given CharSequence is neither null nor of length 0. + * Note: Will return true for a CharSequence that purely consists of whitespace. + *

+	 * StringUtils.hasLength(null) = false
+	 * StringUtils.hasLength("") = false
+	 * StringUtils.hasLength(" ") = true
+	 * StringUtils.hasLength("Hello") = true
+	 * 
+ * @param str the CharSequence to check (may be null) + * @return true if the CharSequence is not null and has length + * @see #hasText(String) + */ + public static boolean hasLength(CharSequence str) { + return (str != null && str.length() > 0); + } + + /** + * Check that the given String is neither null nor of length 0. + * Note: Will return true for a String that purely consists of whitespace. + * @param str the String to check (may be null) + * @return true if the String is not null and has length + * @see #hasLength(CharSequence) + */ + public static boolean hasLength(String str) { + return hasLength((CharSequence) str); + } + + /** + * Check whether the given CharSequence has actual text. + * More specifically, returns true if the string not null, + * its length is greater than 0, and it contains at least one non-whitespace character. + *

+	 * StringUtils.hasText(null) = false
+	 * StringUtils.hasText("") = false
+	 * StringUtils.hasText(" ") = false
+	 * StringUtils.hasText("12345") = true
+	 * StringUtils.hasText(" 12345 ") = true
+	 * 
+ * @param str the CharSequence to check (may be null) + * @return true if the CharSequence is not null, + * its length is greater than 0, and it does not contain whitespace only + * @see java.lang.Character#isWhitespace + */ + public static boolean hasText(CharSequence str) { + if (!hasLength(str)) { + return false; + } + int strLen = str.length(); + for (int i = 0; i < strLen; i++) { + if (!Character.isWhitespace(str.charAt(i))) { + return true; + } + } + return false; + } + + /** + * Check whether the given String has actual text. + * More specifically, returns true if the string not null, + * its length is greater than 0, and it contains at least one non-whitespace character. + * @param str the String to check (may be null) + * @return true if the String is not null, its length is + * greater than 0, and it does not contain whitespace only + * @see #hasText(CharSequence) + */ + public static boolean hasText(String str) { + return hasText((CharSequence) str); + } + + /** + * Check whether the given CharSequence contains any whitespace characters. + * @param str the CharSequence to check (may be null) + * @return true if the CharSequence is not empty and + * contains at least 1 whitespace character + * @see java.lang.Character#isWhitespace + */ + public static boolean containsWhitespace(CharSequence str) { + if (!hasLength(str)) { + return false; + } + int strLen = str.length(); + for (int i = 0; i < strLen; i++) { + if (Character.isWhitespace(str.charAt(i))) { + return true; + } + } + return false; + } + + /** + * Check whether the given String contains any whitespace characters. + * @param str the String to check (may be null) + * @return true if the String is not empty and + * contains at least 1 whitespace character + * @see #containsWhitespace(CharSequence) + */ + public static boolean containsWhitespace(String str) { + return containsWhitespace((CharSequence) str); + } + + /** + * Trim leading and trailing whitespace from the given String. + * @param str the String to check + * @return the trimmed String + * @see java.lang.Character#isWhitespace + */ + public static String trimWhitespace(String str) { + if (!hasLength(str)) { + return str; + } + StringBuffer buf = new StringBuffer(str); + while (buf.length() > 0 && Character.isWhitespace(buf.charAt(0))) { + buf.deleteCharAt(0); + } + while (buf.length() > 0 && Character.isWhitespace(buf.charAt(buf.length() - 1))) { + buf.deleteCharAt(buf.length() - 1); + } + return buf.toString(); + } + + /** + * Trim all whitespace from the given String: + * leading, trailing, and inbetween characters. + * @param str the String to check + * @return the trimmed String + * @see java.lang.Character#isWhitespace + */ + public static String trimAllWhitespace(String str) { + if (!hasLength(str)) { + return str; + } + StringBuffer buf = new StringBuffer(str); + int index = 0; + while (buf.length() > index) { + if (Character.isWhitespace(buf.charAt(index))) { + buf.deleteCharAt(index); + } + else { + index++; + } + } + return buf.toString(); + } + + /** + * Trim leading whitespace from the given String. + * @param str the String to check + * @return the trimmed String + * @see java.lang.Character#isWhitespace + */ + public static String trimLeadingWhitespace(String str) { + if (!hasLength(str)) { + return str; + } + StringBuffer buf = new StringBuffer(str); + while (buf.length() > 0 && Character.isWhitespace(buf.charAt(0))) { + buf.deleteCharAt(0); + } + return buf.toString(); + } + + /** + * Trim trailing whitespace from the given String. + * @param str the String to check + * @return the trimmed String + * @see java.lang.Character#isWhitespace + */ + public static String trimTrailingWhitespace(String str) { + if (!hasLength(str)) { + return str; + } + StringBuffer buf = new StringBuffer(str); + while (buf.length() > 0 && Character.isWhitespace(buf.charAt(buf.length() - 1))) { + buf.deleteCharAt(buf.length() - 1); + } + return buf.toString(); + } + + /** + * Trim all occurences of the supplied leading character from the given String. + * @param str the String to check + * @param leadingCharacter the leading character to be trimmed + * @return the trimmed String + */ + public static String trimLeadingCharacter(String str, char leadingCharacter) { + if (!hasLength(str)) { + return str; + } + StringBuffer buf = new StringBuffer(str); + while (buf.length() > 0 && buf.charAt(0) == leadingCharacter) { + buf.deleteCharAt(0); + } + return buf.toString(); + } + + /** + * Trim all occurences of the supplied trailing character from the given String. + * @param str the String to check + * @param trailingCharacter the trailing character to be trimmed + * @return the trimmed String + */ + public static String trimTrailingCharacter(String str, char trailingCharacter) { + if (!hasLength(str)) { + return str; + } + StringBuffer buf = new StringBuffer(str); + while (buf.length() > 0 && buf.charAt(buf.length() - 1) == trailingCharacter) { + buf.deleteCharAt(buf.length() - 1); + } + return buf.toString(); + } + + + /** + * Test if the given String starts with the specified prefix, + * ignoring upper/lower case. + * @param str the String to check + * @param prefix the prefix to look for + * @see java.lang.String#startsWith + */ + public static boolean startsWithIgnoreCase(String str, String prefix) { + if (str == null || prefix == null) { + return false; + } + if (str.startsWith(prefix)) { + return true; + } + if (str.length() < prefix.length()) { + return false; + } + String lcStr = str.substring(0, prefix.length()).toLowerCase(); + String lcPrefix = prefix.toLowerCase(); + return lcStr.equals(lcPrefix); + } + + /** + * Test if the given String ends with the specified suffix, + * ignoring upper/lower case. + * @param str the String to check + * @param suffix the suffix to look for + * @see java.lang.String#endsWith + */ + public static boolean endsWithIgnoreCase(String str, String suffix) { + if (str == null || suffix == null) { + return false; + } + if (str.endsWith(suffix)) { + return true; + } + if (str.length() < suffix.length()) { + return false; + } + + String lcStr = str.substring(str.length() - suffix.length()).toLowerCase(); + String lcSuffix = suffix.toLowerCase(); + return lcStr.equals(lcSuffix); + } + + /** + * Test whether the given string matches the given substring + * at the given index. + * @param str the original string (or StringBuffer) + * @param index the index in the original string to start matching against + * @param substring the substring to match at the given index + */ + public static boolean substringMatch(CharSequence str, int index, CharSequence substring) { + for (int j = 0; j < substring.length(); j++) { + int i = index + j; + if (i >= str.length() || str.charAt(i) != substring.charAt(j)) { + return false; + } + } + return true; + } + + /** + * Count the occurrences of the substring in string s. + * @param str string to search in. Return 0 if this is null. + * @param sub string to search for. Return 0 if this is null. + */ + public static int countOccurrencesOf(String str, String sub) { + if (str == null || sub == null || str.length() == 0 || sub.length() == 0) { + return 0; + } + int count = 0, pos = 0, idx = 0; + while ((idx = str.indexOf(sub, pos)) != -1) { + ++count; + pos = idx + sub.length(); + } + return count; + } + + /** + * Replace all occurences of a substring within a string with + * another string. + * @param inString String to examine + * @param oldPattern String to replace + * @param newPattern String to insert + * @return a String with the replacements + */ + public static String replace(String inString, String oldPattern, String newPattern) { + if (!hasLength(inString) || !hasLength(oldPattern) || newPattern == null) { + return inString; + } + StringBuffer sbuf = new StringBuffer(); + // output StringBuffer we'll build up + int pos = 0; // our position in the old string + int index = inString.indexOf(oldPattern); + // the index of an occurrence we've found, or -1 + int patLen = oldPattern.length(); + while (index >= 0) { + sbuf.append(inString.substring(pos, index)); + sbuf.append(newPattern); + pos = index + patLen; + index = inString.indexOf(oldPattern, pos); + } + sbuf.append(inString.substring(pos)); + // remember to append any characters to the right of a match + return sbuf.toString(); + } + + /** + * Delete all occurrences of the given substring. + * @param inString the original String + * @param pattern the pattern to delete all occurrences of + * @return the resulting String + */ + public static String delete(String inString, String pattern) { + return replace(inString, pattern, ""); + } + + /** + * Delete any character in a given String. + * @param inString the original String + * @param charsToDelete a set of characters to delete. + * E.g. "az\n" will delete 'a's, 'z's and new lines. + * @return the resulting String + */ + public static String deleteAny(String inString, String charsToDelete) { + if (!hasLength(inString) || !hasLength(charsToDelete)) { + return inString; + } + StringBuffer out = new StringBuffer(); + for (int i = 0; i < inString.length(); i++) { + char c = inString.charAt(i); + if (charsToDelete.indexOf(c) == -1) { + out.append(c); + } + } + return out.toString(); + } + + + //--------------------------------------------------------------------- + // Convenience methods for working with formatted Strings + //--------------------------------------------------------------------- + + /** + * Quote the given String with single quotes. + * @param str the input String (e.g. "myString") + * @return the quoted String (e.g. "'myString'"), + * or null if the input was null + */ + public static String quote(String str) { + return (str != null ? "'" + str + "'" : null); + } + + /** + * Turn the given Object into a String with single quotes + * if it is a String; keeping the Object as-is else. + * @param obj the input Object (e.g. "myString") + * @return the quoted String (e.g. "'myString'"), + * or the input object as-is if not a String + */ + public static Object quoteIfString(Object obj) { + return (obj instanceof String ? quote((String) obj) : obj); + } + + /** + * Unqualify a string qualified by a '.' dot character. For example, + * "this.name.is.qualified", returns "qualified". + * @param qualifiedName the qualified name + */ + public static String unqualify(String qualifiedName) { + return unqualify(qualifiedName, '.'); + } + + /** + * Unqualify a string qualified by a separator character. For example, + * "this:name:is:qualified" returns "qualified" if using a ':' separator. + * @param qualifiedName the qualified name + * @param separator the separator + */ + public static String unqualify(String qualifiedName, char separator) { + return qualifiedName.substring(qualifiedName.lastIndexOf(separator) + 1); + } + + /** + * Capitalize a String, changing the first letter to + * upper case as per {@link Character#toUpperCase(char)}. + * No other letters are changed. + * @param str the String to capitalize, may be null + * @return the capitalized String, null if null + */ + public static String capitalize(String str) { + return changeFirstCharacterCase(str, true); + } + + /** + * Uncapitalize a String, changing the first letter to + * lower case as per {@link Character#toLowerCase(char)}. + * No other letters are changed. + * @param str the String to uncapitalize, may be null + * @return the uncapitalized String, null if null + */ + public static String uncapitalize(String str) { + return changeFirstCharacterCase(str, false); + } + + private static String changeFirstCharacterCase(String str, boolean capitalize) { + if (str == null || str.length() == 0) { + return str; + } + StringBuffer buf = new StringBuffer(str.length()); + if (capitalize) { + buf.append(Character.toUpperCase(str.charAt(0))); + } + else { + buf.append(Character.toLowerCase(str.charAt(0))); + } + buf.append(str.substring(1)); + return buf.toString(); + } + + /** + * Extract the filename from the given path, + * e.g. "mypath/myfile.txt" -> "myfile.txt". + * @param path the file path (may be null) + * @return the extracted filename, or null if none + */ + public static String getFilename(String path) { + if (path == null) { + return null; + } + int separatorIndex = path.lastIndexOf(FOLDER_SEPARATOR); + return (separatorIndex != -1 ? path.substring(separatorIndex + 1) : path); + } + + /** + * Extract the filename extension from the given path, + * e.g. "mypath/myfile.txt" -> "txt". + * @param path the file path (may be null) + * @return the extracted filename extension, or null if none + */ + public static String getFilenameExtension(String path) { + if (path == null) { + return null; + } + int sepIndex = path.lastIndexOf(EXTENSION_SEPARATOR); + return (sepIndex != -1 ? path.substring(sepIndex + 1) : null); + } + + /** + * Strip the filename extension from the given path, + * e.g. "mypath/myfile.txt" -> "mypath/myfile". + * @param path the file path (may be null) + * @return the path with stripped filename extension, + * or null if none + */ + public static String stripFilenameExtension(String path) { + if (path == null) { + return null; + } + int sepIndex = path.lastIndexOf(EXTENSION_SEPARATOR); + return (sepIndex != -1 ? path.substring(0, sepIndex) : path); + } + + /** + * Apply the given relative path to the given path, + * assuming standard Java folder separation (i.e. "/" separators); + * @param path the path to start from (usually a full file path) + * @param relativePath the relative path to apply + * (relative to the full file path above) + * @return the full file path that results from applying the relative path + */ + public static String applyRelativePath(String path, String relativePath) { + int separatorIndex = path.lastIndexOf(FOLDER_SEPARATOR); + if (separatorIndex != -1) { + String newPath = path.substring(0, separatorIndex); + if (!relativePath.startsWith(FOLDER_SEPARATOR)) { + newPath += FOLDER_SEPARATOR; + } + return newPath + relativePath; + } + else { + return relativePath; + } + } + + /** + * Normalize the path by suppressing sequences like "path/.." and + * inner simple dots. + *

The result is convenient for path comparison. For other uses, + * notice that Windows separators ("\") are replaced by simple slashes. + * @param path the original path + * @return the normalized path + */ + public static String cleanPath(String path) { + if (path == null) { + return null; + } + String pathToUse = replace(path, WINDOWS_FOLDER_SEPARATOR, FOLDER_SEPARATOR); + + // Strip prefix from path to analyze, to not treat it as part of the + // first path element. This is necessary to correctly parse paths like + // "file:core/../core/io/Resource.class", where the ".." should just + // strip the first "core" directory while keeping the "file:" prefix. + int prefixIndex = pathToUse.indexOf(":"); + String prefix = ""; + if (prefixIndex != -1) { + prefix = pathToUse.substring(0, prefixIndex + 1); + pathToUse = pathToUse.substring(prefixIndex + 1); + } + if (pathToUse.startsWith(FOLDER_SEPARATOR)) { + prefix = prefix + FOLDER_SEPARATOR; + pathToUse = pathToUse.substring(1); + } + + String[] pathArray = delimitedListToStringArray(pathToUse, FOLDER_SEPARATOR); + List pathElements = new LinkedList(); + int tops = 0; + + for (int i = pathArray.length - 1; i >= 0; i--) { + String element = pathArray[i]; + if (CURRENT_PATH.equals(element)) { + // Points to current directory - drop it. + } + else if (TOP_PATH.equals(element)) { + // Registering top path found. + tops++; + } + else { + if (tops > 0) { + // Merging path element with element corresponding to top path. + tops--; + } + else { + // Normal path element found. + pathElements.add(0, element); + } + } + } + + // Remaining top paths need to be retained. + for (int i = 0; i < tops; i++) { + pathElements.add(0, TOP_PATH); + } + + return prefix + collectionToDelimitedString(pathElements, FOLDER_SEPARATOR); + } + + /** + * Compare two paths after normalization of them. + * @param path1 first path for comparison + * @param path2 second path for comparison + * @return whether the two paths are equivalent after normalization + */ + public static boolean pathEquals(String path1, String path2) { + return cleanPath(path1).equals(cleanPath(path2)); + } + + /** + * Parse the given localeString into a {@link Locale}. + *

This is the inverse operation of {@link Locale#toString Locale's toString}. + * @param localeString the locale string, following Locale's + * toString() format ("en", "en_UK", etc); + * also accepts spaces as separators, as an alternative to underscores + * @return a corresponding Locale instance + */ + public static Locale parseLocaleString(String localeString) { + String[] parts = tokenizeToStringArray(localeString, "_ ", false, false); + String language = (parts.length > 0 ? parts[0] : ""); + String country = (parts.length > 1 ? parts[1] : ""); + String variant = ""; + if (parts.length >= 2) { + // There is definitely a variant, and it is everything after the country + // code sans the separator between the country code and the variant. + int endIndexOfCountryCode = localeString.indexOf(country) + country.length(); + // Strip off any leading '_' and whitespace, what's left is the variant. + variant = trimLeadingWhitespace(localeString.substring(endIndexOfCountryCode)); + if (variant.startsWith("_")) { + variant = trimLeadingCharacter(variant, '_'); + } + } + return (language.length() > 0 ? new Locale(language, country, variant) : null); + } + + /** + * Determine the RFC 3066 compliant language tag, + * as used for the HTTP "Accept-Language" header. + * @param locale the Locale to transform to a language tag + * @return the RFC 3066 compliant language tag as String + */ + public static String toLanguageTag(Locale locale) { + return locale.getLanguage() + (hasText(locale.getCountry()) ? "-" + locale.getCountry() : ""); + } + + + //--------------------------------------------------------------------- + // Convenience methods for working with String arrays + //--------------------------------------------------------------------- + + /** + * Append the given String to the given String array, returning a new array + * consisting of the input array contents plus the given String. + * @param array the array to append to (can be null) + * @param str the String to append + * @return the new array (never null) + */ + public static String[] addStringToArray(String[] array, String str) { + if (ObjectUtils.isEmpty(array)) { + return new String[] {str}; + } + String[] newArr = new String[array.length + 1]; + System.arraycopy(array, 0, newArr, 0, array.length); + newArr[array.length] = str; + return newArr; + } + + /** + * Concatenate the given String arrays into one, + * with overlapping array elements included twice. + *

The order of elements in the original arrays is preserved. + * @param array1 the first array (can be null) + * @param array2 the second array (can be null) + * @return the new array (null if both given arrays were null) + */ + public static String[] concatenateStringArrays(String[] array1, String[] array2) { + if (ObjectUtils.isEmpty(array1)) { + return array2; + } + if (ObjectUtils.isEmpty(array2)) { + return array1; + } + String[] newArr = new String[array1.length + array2.length]; + System.arraycopy(array1, 0, newArr, 0, array1.length); + System.arraycopy(array2, 0, newArr, array1.length, array2.length); + return newArr; + } + + /** + * Merge the given String arrays into one, with overlapping + * array elements only included once. + *

The order of elements in the original arrays is preserved + * (with the exception of overlapping elements, which are only + * included on their first occurence). + * @param array1 the first array (can be null) + * @param array2 the second array (can be null) + * @return the new array (null if both given arrays were null) + */ + public static String[] mergeStringArrays(String[] array1, String[] array2) { + if (ObjectUtils.isEmpty(array1)) { + return array2; + } + if (ObjectUtils.isEmpty(array2)) { + return array1; + } + List result = new ArrayList(); + result.addAll(Arrays.asList(array1)); + for (int i = 0; i < array2.length; i++) { + String str = array2[i]; + if (!result.contains(str)) { + result.add(str); + } + } + return toStringArray(result); + } + + /** + * Turn given source String array into sorted array. + * @param array the source array + * @return the sorted array (never null) + */ + public static String[] sortStringArray(String[] array) { + if (ObjectUtils.isEmpty(array)) { + return new String[0]; + } + Arrays.sort(array); + return array; + } + + /** + * Copy the given Collection into a String array. + * The Collection must contain String elements only. + * @param collection the Collection to copy + * @return the String array (null if the passed-in + * Collection was null) + */ + public static String[] toStringArray(Collection collection) { + if (collection == null) { + return null; + } + return (String[]) collection.toArray(new String[collection.size()]); + } + + /** + * Copy the given Enumeration into a String array. + * The Enumeration must contain String elements only. + * @param enumeration the Enumeration to copy + * @return the String array (null if the passed-in + * Enumeration was null) + */ + public static String[] toStringArray(Enumeration enumeration) { + if (enumeration == null) { + return null; + } + List list = Collections.list(enumeration); + return (String[]) list.toArray(new String[list.size()]); + } + + /** + * Trim the elements of the given String array, + * calling String.trim() on each of them. + * @param array the original String array + * @return the resulting array (of the same size) with trimmed elements + */ + public static String[] trimArrayElements(String[] array) { + if (ObjectUtils.isEmpty(array)) { + return new String[0]; + } + String[] result = new String[array.length]; + for (int i = 0; i < array.length; i++) { + String element = array[i]; + result[i] = (element != null ? element.trim() : null); + } + return result; + } + + /** + * Remove duplicate Strings from the given array. + * Also sorts the array, as it uses a TreeSet. + * @param array the String array + * @return an array without duplicates, in natural sort order + */ + public static String[] removeDuplicateStrings(String[] array) { + if (ObjectUtils.isEmpty(array)) { + return array; + } + Set set = new TreeSet(); + for (int i = 0; i < array.length; i++) { + set.add(array[i]); + } + return toStringArray(set); + } + + /** + * Split a String at the first occurrence of the delimiter. + * Does not include the delimiter in the result. + * @param toSplit the string to split + * @param delimiter to split the string up with + * @return a two element array with index 0 being before the delimiter, and + * index 1 being after the delimiter (neither element includes the delimiter); + * or null if the delimiter wasn't found in the given input String + */ + public static String[] split(String toSplit, String delimiter) { + if (!hasLength(toSplit) || !hasLength(delimiter)) { + return null; + } + int offset = toSplit.indexOf(delimiter); + if (offset < 0) { + return null; + } + String beforeDelimiter = toSplit.substring(0, offset); + String afterDelimiter = toSplit.substring(offset + delimiter.length()); + return new String[] {beforeDelimiter, afterDelimiter}; + } + + /** + * Take an array Strings and split each element based on the given delimiter. + * A Properties instance is then generated, with the left of the + * delimiter providing the key, and the right of the delimiter providing the value. + *

Will trim both the key and value before adding them to the + * Properties instance. + * @param array the array to process + * @param delimiter to split each element using (typically the equals symbol) + * @return a Properties instance representing the array contents, + * or null if the array to process was null or empty + */ + public static Properties splitArrayElementsIntoProperties(String[] array, String delimiter) { + return splitArrayElementsIntoProperties(array, delimiter, null); + } + + /** + * Take an array Strings and split each element based on the given delimiter. + * A Properties instance is then generated, with the left of the + * delimiter providing the key, and the right of the delimiter providing the value. + *

Will trim both the key and value before adding them to the + * Properties instance. + * @param array the array to process + * @param delimiter to split each element using (typically the equals symbol) + * @param charsToDelete one or more characters to remove from each element + * prior to attempting the split operation (typically the quotation mark + * symbol), or null if no removal should occur + * @return a Properties instance representing the array contents, + * or null if the array to process was null or empty + */ + public static Properties splitArrayElementsIntoProperties( + String[] array, String delimiter, String charsToDelete) { + + if (ObjectUtils.isEmpty(array)) { + return null; + } + Properties result = new Properties(); + for (int i = 0; i < array.length; i++) { + String element = array[i]; + if (charsToDelete != null) { + element = deleteAny(array[i], charsToDelete); + } + String[] splittedElement = split(element, delimiter); + if (splittedElement == null) { + continue; + } + result.setProperty(splittedElement[0].trim(), splittedElement[1].trim()); + } + return result; + } + + /** + * Tokenize the given String into a String array via a StringTokenizer. + * Trims tokens and omits empty tokens. + *

The given delimiters string is supposed to consist of any number of + * delimiter characters. Each of those characters can be used to separate + * tokens. A delimiter is always a single character; for multi-character + * delimiters, consider using delimitedListToStringArray + * @param str the String to tokenize + * @param delimiters the delimiter characters, assembled as String + * (each of those characters is individually considered as delimiter). + * @return an array of the tokens + * @see java.util.StringTokenizer + * @see java.lang.String#trim() + * @see #delimitedListToStringArray + */ + public static String[] tokenizeToStringArray(String str, String delimiters) { + return tokenizeToStringArray(str, delimiters, true, true); + } + + /** + * Tokenize the given String into a String array via a StringTokenizer. + *

The given delimiters string is supposed to consist of any number of + * delimiter characters. Each of those characters can be used to separate + * tokens. A delimiter is always a single character; for multi-character + * delimiters, consider using delimitedListToStringArray + * @param str the String to tokenize + * @param delimiters the delimiter characters, assembled as String + * (each of those characters is individually considered as delimiter) + * @param trimTokens trim the tokens via String's trim + * @param ignoreEmptyTokens omit empty tokens from the result array + * (only applies to tokens that are empty after trimming; StringTokenizer + * will not consider subsequent delimiters as token in the first place). + * @return an array of the tokens (null if the input String + * was null) + * @see java.util.StringTokenizer + * @see java.lang.String#trim() + * @see #delimitedListToStringArray + */ + public static String[] tokenizeToStringArray( + String str, String delimiters, boolean trimTokens, boolean ignoreEmptyTokens) { + + if (str == null) { + return null; + } + StringTokenizer st = new StringTokenizer(str, delimiters); + List tokens = new ArrayList(); + while (st.hasMoreTokens()) { + String token = st.nextToken(); + if (trimTokens) { + token = token.trim(); + } + if (!ignoreEmptyTokens || token.length() > 0) { + tokens.add(token); + } + } + return toStringArray(tokens); + } + + /** + * Take a String which is a delimited list and convert it to a String array. + *

A single delimiter can consists of more than one character: It will still + * be considered as single delimiter string, rather than as bunch of potential + * delimiter characters - in contrast to tokenizeToStringArray. + * @param str the input String + * @param delimiter the delimiter between elements (this is a single delimiter, + * rather than a bunch individual delimiter characters) + * @return an array of the tokens in the list + * @see #tokenizeToStringArray + */ + public static String[] delimitedListToStringArray(String str, String delimiter) { + return delimitedListToStringArray(str, delimiter, null); + } + + /** + * Take a String which is a delimited list and convert it to a String array. + *

A single delimiter can consists of more than one character: It will still + * be considered as single delimiter string, rather than as bunch of potential + * delimiter characters - in contrast to tokenizeToStringArray. + * @param str the input String + * @param delimiter the delimiter between elements (this is a single delimiter, + * rather than a bunch individual delimiter characters) + * @param charsToDelete a set of characters to delete. Useful for deleting unwanted + * line breaks: e.g. "\r\n\f" will delete all new lines and line feeds in a String. + * @return an array of the tokens in the list + * @see #tokenizeToStringArray + */ + public static String[] delimitedListToStringArray(String str, String delimiter, String charsToDelete) { + if (str == null) { + return new String[0]; + } + if (delimiter == null) { + return new String[] {str}; + } + List result = new ArrayList(); + if ("".equals(delimiter)) { + for (int i = 0; i < str.length(); i++) { + result.add(deleteAny(str.substring(i, i + 1), charsToDelete)); + } + } + else { + int pos = 0; + int delPos = 0; + while ((delPos = str.indexOf(delimiter, pos)) != -1) { + result.add(deleteAny(str.substring(pos, delPos), charsToDelete)); + pos = delPos + delimiter.length(); + } + if (str.length() > 0 && pos <= str.length()) { + // Add rest of String, but not in case of empty input. + result.add(deleteAny(str.substring(pos), charsToDelete)); + } + } + return toStringArray(result); + } + + /** + * Convert a CSV list into an array of Strings. + * @param str the input String + * @return an array of Strings, or the empty array in case of empty input + */ + public static String[] commaDelimitedListToStringArray(String str) { + return delimitedListToStringArray(str, ","); + } + + /** + * Convenience method to convert a CSV string list to a set. + * Note that this will suppress duplicates. + * @param str the input String + * @return a Set of String entries in the list + */ + public static Set commaDelimitedListToSet(String str) { + Set set = new TreeSet(); + String[] tokens = commaDelimitedListToStringArray(str); + for (int i = 0; i < tokens.length; i++) { + set.add(tokens[i]); + } + return set; + } + + /** + * Convenience method to return a Collection as a delimited (e.g. CSV) + * String. E.g. useful for toString() implementations. + * @param coll the Collection to display + * @param delim the delimiter to use (probably a ",") + * @param prefix the String to start each element with + * @param suffix the String to end each element with + * @return the delimited String + */ + public static String collectionToDelimitedString(Collection coll, String delim, String prefix, String suffix) { + if (CollectionUtils.isEmpty(coll)) { + return ""; + } + StringBuffer sb = new StringBuffer(); + Iterator it = coll.iterator(); + while (it.hasNext()) { + sb.append(prefix).append(it.next()).append(suffix); + if (it.hasNext()) { + sb.append(delim); + } + } + return sb.toString(); + } + + /** + * Convenience method to return a Collection as a delimited (e.g. CSV) + * String. E.g. useful for toString() implementations. + * @param coll the Collection to display + * @param delim the delimiter to use (probably a ",") + * @return the delimited String + */ + public static String collectionToDelimitedString(Collection coll, String delim) { + return collectionToDelimitedString(coll, delim, "", ""); + } + + /** + * Convenience method to return a Collection as a CSV String. + * E.g. useful for toString() implementations. + * @param coll the Collection to display + * @return the delimited String + */ + public static String collectionToCommaDelimitedString(Collection coll) { + return collectionToDelimitedString(coll, ","); + } + + /** + * Convenience method to return a String array as a delimited (e.g. CSV) + * String. E.g. useful for toString() implementations. + * @param arr the array to display + * @param delim the delimiter to use (probably a ",") + * @return the delimited String + */ + public static String arrayToDelimitedString(Object[] arr, String delim) { + if (ObjectUtils.isEmpty(arr)) { + return ""; + } + StringBuffer sb = new StringBuffer(); + for (int i = 0; i < arr.length; i++) { + if (i > 0) { + sb.append(delim); + } + sb.append(arr[i]); + } + return sb.toString(); + } + + /** + * Convenience method to return a String array as a CSV String. + * E.g. useful for toString() implementations. + * @param arr the array to display + * @return the delimited String + */ + public static String arrayToCommaDelimitedString(Object[] arr) { + return arrayToDelimitedString(arr, ","); + } + +} Index: 3rdParty_sources/spring/org/springframework/util/StringValueResolver.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/util/StringValueResolver.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/util/StringValueResolver.java 17 Aug 2012 15:16:11 -0000 1.1 @@ -0,0 +1,38 @@ +/* + * 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.util; + +/** + * Simple strategy interface for resolving a String value. + * Used by {@link org.springframework.beans.factory.config.ConfigurableBeanFactory}. + * + * @author Juergen Hoeller + * @since 2.5 + * @see org.springframework.beans.factory.config.ConfigurableBeanFactory#resolveAliases + * @see org.springframework.beans.factory.config.BeanDefinitionVisitor#BeanDefinitionVisitor(StringValueResolver) + * @see org.springframework.beans.factory.config.PropertyPlaceholderConfigurer + */ +public interface StringValueResolver { + + /** + * Resolve the given String value, for example parsing placeholders. + * @param strVal the original String value + * @return the resolved String value + */ + String resolveStringValue(String strVal); + +} Index: 3rdParty_sources/spring/org/springframework/util/SystemPropertyUtils.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/util/SystemPropertyUtils.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/util/SystemPropertyUtils.java 17 Aug 2012 15:16:10 -0000 1.1 @@ -0,0 +1,86 @@ +/* + * 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.util; + +/** + * Helper class for resolving placeholders in texts. Usually applied to file paths. + * + *

A text may contain ${...} placeholders, to be resolved as + * system properties: e.g. ${user.dir}. + * + * @author Juergen Hoeller + * @since 1.2.5 + * @see #PLACEHOLDER_PREFIX + * @see #PLACEHOLDER_SUFFIX + * @see System#getProperty(String) + */ +public abstract class SystemPropertyUtils { + + /** Prefix for system property placeholders: "${" */ + public static final String PLACEHOLDER_PREFIX = "${"; + + /** Suffix for system property placeholders: "}" */ + public static final String PLACEHOLDER_SUFFIX = "}"; + + + /** + * Resolve ${...} placeholders in the given text, + * replacing them with corresponding system property values. + * @param text the String to resolve + * @return the resolved String + * @see #PLACEHOLDER_PREFIX + * @see #PLACEHOLDER_SUFFIX + */ + public static String resolvePlaceholders(String text) { + StringBuffer buf = new StringBuffer(text); + + int startIndex = buf.indexOf(PLACEHOLDER_PREFIX); + while (startIndex != -1) { + int endIndex = buf.indexOf(PLACEHOLDER_SUFFIX, startIndex + PLACEHOLDER_PREFIX.length()); + if (endIndex != -1) { + String placeholder = buf.substring(startIndex + PLACEHOLDER_PREFIX.length(), endIndex); + int nextIndex = endIndex + PLACEHOLDER_SUFFIX.length(); + try { + String propVal = System.getProperty(placeholder); + if (propVal == null) { + // Fall back to searching the system environment. + propVal = System.getenv(placeholder); + } + if (propVal != null) { + buf.replace(startIndex, endIndex + PLACEHOLDER_SUFFIX.length(), propVal); + nextIndex = startIndex + propVal.length(); + } + else { + System.err.println("Could not resolve placeholder '" + placeholder + "' in [" + text + + "] as system property: neither system property nor environment variable found"); + } + } + catch (Throwable ex) { + System.err.println("Could not resolve placeholder '" + placeholder + "' in [" + text + + "] as system property: " + ex); + } + startIndex = buf.indexOf(PLACEHOLDER_PREFIX, nextIndex); + } + else { + startIndex = -1; + } + } + + return buf.toString(); + } + +} Index: 3rdParty_sources/spring/org/springframework/util/TypeUtils.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/util/TypeUtils.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/util/TypeUtils.java 17 Aug 2012 15:16:09 -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.util; + +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.lang.reflect.WildcardType; + +/** + * Utility to work with Java 5 generic type parameters. + * Mainly for internal use within the framework. + * + * @author Ramnivas Laddad + * @author Juergen Hoeller + * @since 2.0.7 + */ +public abstract class TypeUtils { + + /** + * Check if the right-hand side type may be assigned to the left-hand side + * type following the Java generics rules. + * @param lhsType the target type + * @param rhsType the value type that should be assigned to the target type + * @return true if rhs is assignable to lhs + */ + public static boolean isAssignable(Type lhsType, Type rhsType) { + Assert.notNull(lhsType, "Left-hand side type must not be null"); + Assert.notNull(rhsType, "Right-hand side type must not be null"); + if (lhsType.equals(rhsType)) { + return true; + } + if (lhsType instanceof Class && rhsType instanceof Class) { + return ClassUtils.isAssignable((Class) lhsType, (Class) rhsType); + } + if (lhsType instanceof ParameterizedType && rhsType instanceof ParameterizedType) { + return isAssignable((ParameterizedType) lhsType, (ParameterizedType) rhsType); + } + if (lhsType instanceof WildcardType) { + return isAssignable((WildcardType) lhsType, rhsType); + } + return false; + } + + private static boolean isAssignable(ParameterizedType lhsType, ParameterizedType rhsType) { + if (lhsType.equals(rhsType)) { + return true; + } + Type[] lhsTypeArguments = lhsType.getActualTypeArguments(); + Type[] rhsTypeArguments = rhsType.getActualTypeArguments(); + if (lhsTypeArguments.length != rhsTypeArguments.length) { + return false; + } + for (int size = lhsTypeArguments.length, i = 0; i < size; ++i) { + Type lhsArg = lhsTypeArguments[i]; + Type rhsArg = rhsTypeArguments[i]; + if (!lhsArg.equals(rhsArg) && + !(lhsArg instanceof WildcardType && isAssignable((WildcardType) lhsArg, rhsArg))) { + return false; + } + } + return true; + } + + private static boolean isAssignable(WildcardType lhsType, Type rhsType) { + Type[] upperBounds = lhsType.getUpperBounds(); + Type[] lowerBounds = lhsType.getLowerBounds(); + for (int size = upperBounds.length, i = 0; i < size; ++i) { + if (!isAssignable(upperBounds[i], rhsType)) { + return false; + } + } + for (int size = lowerBounds.length, i = 0; i < size; ++i) { + if (!isAssignable(rhsType, lowerBounds[i])) { + return false; + } + } + return true; + } + +} Index: 3rdParty_sources/spring/org/springframework/util/WeakReferenceMonitor.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/util/WeakReferenceMonitor.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/util/WeakReferenceMonitor.java 17 Aug 2012 15:16:09 -0000 1.1 @@ -0,0 +1,169 @@ +/* + * 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.util; + +import java.lang.ref.Reference; +import java.lang.ref.ReferenceQueue; +import java.lang.ref.WeakReference; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * Track references to arbitrary objects using proxy and weak references. To + * monitor a handle, one should call {@link #monitor(Object, ReleaseListener)}, + * with the given handle object usually being a holder that uses the target + * object underneath, and the release listener performing cleanup of the + * target object once the handle is not strongly referenced anymore. + * + *

When a given handle becomes weakly reachable, the specified listener + * will be called by a background thread. This thread will only be started + * lazily and will be stopped once no handles are registered for monitoring + * anymore, to be restarted if further handles are added. + * + *

Thanks to Tomasz Wysocki for the suggestion and the original + * implementation of this class! + * + * @author Colin Sampaleanu + * @author Juergen Hoeller + * @since 1.2 + * @see #monitor + */ +public class WeakReferenceMonitor { + + private static final Log logger = LogFactory.getLog(WeakReferenceMonitor.class); + + // Queue receiving reachability events + private static final ReferenceQueue handleQueue = new ReferenceQueue(); + + // All tracked entries (WeakReference => ReleaseListener) + private static final Map trackedEntries = Collections.synchronizedMap(new HashMap()); + + // Thread polling handleQueue, lazy initialized + private static Thread monitoringThread = null; + + + /** + * Start to monitor given handle object for becoming weakly reachable. + * When the handle isn't used anymore, the given listener will be called. + * @param handle the object that will be monitored + * @param listener the listener that will be called upon release of the handle + */ + public static void monitor(Object handle, ReleaseListener listener) { + if (logger.isDebugEnabled()) { + logger.debug("Monitoring handle [" + handle + "] with release listener [" + listener + "]"); + } + + // Make weak reference to this handle, so we can say when + // handle is not used any more by polling on handleQueue. + WeakReference weakRef = new WeakReference(handle, handleQueue); + + // Add monitored entry to internal map of all monitored entries. + addEntry(weakRef, listener); + } + + /** + * Add entry to internal map of tracked entries. + * Internal monitoring thread is started if not already running. + * @param ref reference to tracked handle + * @param entry the associated entry + */ + private static void addEntry(Reference ref, ReleaseListener entry) { + // Add entry, the key is given reference. + trackedEntries.put(ref, entry); + + // Start monitoring thread lazily. + synchronized (WeakReferenceMonitor.class) { + if (!isMonitoringThreadRunning()) { + monitoringThread = new Thread(new MonitoringProcess(), WeakReferenceMonitor.class.getName()); + monitoringThread.setDaemon(true); + monitoringThread.start(); + } + } + } + + /** + * Remove entry from internal map of tracked entries. + * @param reference the reference that should be removed + * @return entry object associated with given reference + */ + private static ReleaseListener removeEntry(Reference reference) { + return (ReleaseListener) trackedEntries.remove(reference); + } + + /** + * Check if monitoring thread is currently running. + */ + private static boolean isMonitoringThreadRunning() { + synchronized (WeakReferenceMonitor.class) { + return (monitoringThread != null); + } + } + + + /** + * Thread implementation that performs the actual monitoring. + */ + private static class MonitoringProcess implements Runnable { + + public void run() { + logger.debug("Starting reference monitor thread"); + try { + // Check if there are any tracked entries left. + while (!trackedEntries.isEmpty()) { + try { + Reference reference = handleQueue.remove(); + // Stop tracking this reference. + ReleaseListener entry = removeEntry(reference); + if (entry != null) { + // Invoke listener callback. + entry.released(); + } + } + catch (InterruptedException ex) { + logger.debug("Reference monitor thread interrupted", ex); + break; + } + } + } + finally { + logger.debug("Stopping reference monitor thread"); + synchronized (WeakReferenceMonitor.class) { + monitoringThread = null; + } + } + } + } + + + /** + * Listener that is notified when the handle is being released. + * To be implemented by users of this reference monitor. + */ + public static interface ReleaseListener { + + /** + * This callback method is invoked once the associated handle has been released, + * i.e. once there are no monitored strong references to the handle anymore. + */ + void released(); + } + +} Index: 3rdParty_sources/spring/org/springframework/util/package.html =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/util/package.html,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/util/package.html 17 Aug 2012 15:16:10 -0000 1.1 @@ -0,0 +1,8 @@ + + + +Miscellaneous utility classes, such as String manipulation utilities, +a Log4J configurer, and a state holder for paged lists of objects. + + + Index: 3rdParty_sources/spring/org/springframework/util/comparator/BooleanComparator.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/util/comparator/BooleanComparator.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/util/comparator/BooleanComparator.java 17 Aug 2012 15:16:03 -0000 1.1 @@ -0,0 +1,85 @@ +/* + * 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.util.comparator; + +import java.io.Serializable; +import java.util.Comparator; + +/** + * A Comparator for Boolean objects that can sort either true or false first. + * + * @author Keith Donald + * @since 1.2.2 + */ +public final class BooleanComparator implements Comparator, Serializable { + + /** + * A shared default instance of this comparator, treating true lower + * than false. + */ + public static final BooleanComparator TRUE_LOW = new BooleanComparator(true); + + /** + * A shared default instance of this comparator, treating true higher + * than false. + */ + public static final BooleanComparator TRUE_HIGH = new BooleanComparator(false); + + + private final boolean trueLow; + + + /** + * Create a BooleanComparator that sorts boolean values based on + * the provided flag. + *

Alternatively, you can use the default shared instances: + * BooleanComparator.TRUE_LOW and + * BooleanComparator.TRUE_HIGH. + * @param trueLow whether to treat true as lower or higher than false + * @see #TRUE_LOW + * @see #TRUE_HIGH + */ + public BooleanComparator(boolean trueLow) { + this.trueLow = trueLow; + } + + + public int compare(Object o1, Object o2) { + boolean v1 = ((Boolean) o1).booleanValue(); + boolean v2 = ((Boolean) o2).booleanValue(); + return (v1 ^ v2) ? ((v1 ^ this.trueLow) ? 1 : -1) : 0; + } + + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof BooleanComparator)) { + return false; + } + return (this.trueLow == ((BooleanComparator) obj).trueLow); + } + + public int hashCode() { + return (this.trueLow ? -1 : 1) * getClass().hashCode(); + } + + public String toString() { + return "BooleanComparator: " + (this.trueLow ? "true low" : "true high"); + } + +} Index: 3rdParty_sources/spring/org/springframework/util/comparator/ComparableComparator.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/util/comparator/ComparableComparator.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/util/comparator/ComparableComparator.java 17 Aug 2012 15:16:03 -0000 1.1 @@ -0,0 +1,40 @@ +/* + * 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.util.comparator; + +import java.util.Comparator; + +import org.springframework.util.Assert; + +/** + * Comparator that adapts Comparables to the Comparator interface. + * Mainly for internal use in other Comparators, when supposed + * to work on Comparables. + * + * @author Keith Donald + * @since 1.2.2 + * @see Comparable + */ +public class ComparableComparator implements Comparator { + + public int compare(Object o1, Object o2) { + Assert.isTrue(o1 instanceof Comparable, "The first object provided is not Comparable"); + Assert.isTrue(o2 instanceof Comparable, "The second object provided is not Comparable"); + return ((Comparable) o1).compareTo(o2); + } + +} Index: 3rdParty_sources/spring/org/springframework/util/comparator/CompoundComparator.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/util/comparator/CompoundComparator.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/util/comparator/CompoundComparator.java 17 Aug 2012 15:16:03 -0000 1.1 @@ -0,0 +1,206 @@ +/* + * 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.util.comparator; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.Iterator; +import java.util.List; + +import org.springframework.util.Assert; + +/** + * A comparator that chains a sequence of one or more more Comparators. + * + *

A compound comparator calls each Comparator in sequence until a single + * Comparator returns a non-zero result, or the comparators are exhausted and + * zero is returned. + * + *

This facilitates in-memory sorting similar to multi-column sorting in SQL. + * The order of any single Comparator in the list can also be reversed. + * + * @author Keith Donald + * @author Juergen Hoeller + * @since 1.2.2 + */ +public class CompoundComparator implements Comparator, Serializable { + + private final List comparators; + + + /** + * Construct a CompoundComparator with initially no Comparators. Clients + * must add at least one Comparator before calling the compare method or an + * IllegalStateException is thrown. + */ + public CompoundComparator() { + this.comparators = new ArrayList(); + } + + /** + * Construct a CompoundComparator from the Comparators in the provided array. + *

All Comparators will default to ascending sort order, + * unless they are InvertibleComparators. + * @param comparators the comparators to build into a compound comparator + * @see InvertibleComparator + */ + public CompoundComparator(Comparator[] comparators) { + this.comparators = new ArrayList(comparators.length); + for (int i = 0; i < comparators.length; i++) { + addComparator(comparators[i]); + } + } + + + /** + * Add a Comparator to the end of the chain. + *

The Comparator will default to ascending sort order, + * unless it is a InvertibleComparator. + * @param comparator the Comparator to add to the end of the chain + * @see InvertibleComparator + */ + public void addComparator(Comparator comparator) { + if (comparator instanceof InvertibleComparator) { + this.comparators.add(comparator); + } + else { + this.comparators.add(new InvertibleComparator(comparator)); + } + } + + /** + * Add a Comparator to the end of the chain using the provided sort order. + * @param comparator the Comparator to add to the end of the chain + * @param ascending the sort order: ascending (true) or descending (false) + */ + public void addComparator(Comparator comparator, boolean ascending) { + this.comparators.add(new InvertibleComparator(comparator, ascending)); + } + + /** + * Replace the Comparator at the given index. + *

The Comparator will default to ascending sort order, + * unless it is a InvertibleComparator. + * @param index the index of the Comparator to replace + * @param comparator the Comparator to place at the given index + * @see InvertibleComparator + */ + public void setComparator(int index, Comparator comparator) { + if (comparator instanceof InvertibleComparator) { + this.comparators.set(index, comparator); + } + else { + InvertibleComparator invComp = new InvertibleComparator(comparator); + this.comparators.set(index, invComp); + } + } + + /** + * Replace the Comparator at the given index using the given sort order. + * @param index the index of the Comparator to replace + * @param comparator the Comparator to place at the given index + * @param ascending the sort order: ascending (true) or descending (false) + */ + public void setComparator(int index, Comparator comparator, boolean ascending) { + InvertibleComparator invComp = new InvertibleComparator(comparator, ascending); + this.comparators.set(index, invComp); + } + + /** + * Invert the sort order of each sort definition contained by this compound + * comparator. + */ + public void invertOrder() { + Iterator it = this.comparators.iterator(); + while (it.hasNext()) { + ((InvertibleComparator) it.next()).invertOrder(); + } + } + + /** + * Invert the sort order of the sort definition at the specified index. + * @param index the index of the comparator to invert + */ + public void invertOrder(int index) { + getInvertibleComparator(index).invertOrder(); + } + + /** + * Change the sort order at the given index to ascending. + * @param index the index of the comparator to change + */ + public void setAscendingOrder(int index) { + getInvertibleComparator(index).setAscending(true); + } + + /** + * Change the sort order at the given index to descending sort. + * @param index the index of the comparator to change + */ + public void setDescendingOrder(int index) { + getInvertibleComparator(index).setAscending(false); + } + + /** + * Return the InvertibleComparator for the given index, if any. + */ + private InvertibleComparator getInvertibleComparator(int index) { + return (InvertibleComparator) this.comparators.get(index); + } + + /** + * Returns the number of aggregated comparators. + */ + public int getComparatorCount() { + return comparators.size(); + } + + + public int compare(Object o1, Object o2) { + Assert.state(this.comparators.size() > 0, + "No sort definitions have been added to this CompoundComparator to compare"); + for (Iterator it = this.comparators.iterator(); it.hasNext();) { + InvertibleComparator def = (InvertibleComparator) it.next(); + int result = def.compare(o1, o2); + if (result != 0) { + return result; + } + } + return 0; + } + + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof CompoundComparator)) { + return false; + } + CompoundComparator other = (CompoundComparator) obj; + return this.comparators.equals(other.comparators); + } + + public int hashCode() { + return this.comparators.hashCode(); + } + + public String toString() { + return "CompoundComparator: " + this.comparators; + } + +} Index: 3rdParty_sources/spring/org/springframework/util/comparator/InvertibleComparator.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/util/comparator/InvertibleComparator.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/util/comparator/InvertibleComparator.java 17 Aug 2012 15:16:04 -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.util.comparator; + +import java.io.Serializable; +import java.util.Comparator; + +/** + * A decorator for a comparator, with an "ascending" flag denoting + * whether comparison results should be treated in forward (standard + * ascending) order or flipped for reverse (descending) order. + * + * @author Keith Donald + * @author Juergen Hoeller + * @since 1.2.2 + */ +public class InvertibleComparator implements Comparator, Serializable { + + private final Comparator comparator; + + private boolean ascending = true; + + + /** + * Create an InvertibleComparator that sorts ascending by default. + * For the actual comparison, the specified Comparator will be used. + * @param comparator the comparator to decorate + */ + public InvertibleComparator(Comparator comparator) { + this.comparator = comparator; + } + + /** + * Create an InvertibleComparator that sorts based on the provided order. + * For the actual comparison, the specified Comparator will be used. + * @param comparator the comparator to decorate + * @param ascending the sort order: ascending (true) or descending (false) + */ + public InvertibleComparator(Comparator comparator, boolean ascending) { + this.comparator = comparator; + setAscending(ascending); + } + + + /** + * Specify the sort order: ascending (true) or descending (false). + */ + public void setAscending(boolean ascending) { + this.ascending = ascending; + } + + /** + * Return the sort order: ascending (true) or descending (false). + */ + public boolean isAscending() { + return ascending; + } + + /** + * Invert the sort order: ascending -> descending or + * descending -> ascending. + */ + public void invertOrder() { + this.ascending = !this.ascending; + } + + + public int compare(Object o1, Object o2) { + int result = this.comparator.compare(o1, o2); + if (result != 0) { + // Invert the order if it is a reverse sort. + if (!this.ascending) { + if (Integer.MIN_VALUE == result) { + result = Integer.MAX_VALUE; + } + else { + result *= -1; + } + } + return result; + } + return 0; + } + + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof InvertibleComparator)) { + return false; + } + InvertibleComparator other = (InvertibleComparator) obj; + return (this.comparator.equals(other.comparator) && this.ascending == other.ascending); + } + + public int hashCode() { + return this.comparator.hashCode(); + } + + public String toString() { + return "InvertibleComparator: [" + this.comparator + "]; ascending=" + this.ascending; + } + +} Index: 3rdParty_sources/spring/org/springframework/util/comparator/NullSafeComparator.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/util/comparator/NullSafeComparator.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/util/comparator/NullSafeComparator.java 17 Aug 2012 15:16:03 -0000 1.1 @@ -0,0 +1,119 @@ +/* + * 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.util.comparator; + +import java.util.Comparator; + +import org.springframework.util.Assert; + +/** + * A Comparator that will safely compare nulls to be lower or higher than + * other objects. Can decorate a given Comparator or work on Comparables. + * + * @author Keith Donald + * @author Juergen Hoeller + * @since 1.2.2 + * @see Comparable + */ +public class NullSafeComparator implements Comparator { + + /** + * A shared default instance of this comparator, treating nulls lower + * than non-null objects. + */ + public static final NullSafeComparator NULLS_LOW = new NullSafeComparator(true); + + /** + * A shared default instance of this comparator, treating nulls higher + * than non-null objects. + */ + public static final NullSafeComparator NULLS_HIGH = new NullSafeComparator(false); + + + private final Comparator nonNullComparator; + + private final boolean nullsLow; + + + /** + * Create a NullSafeComparator that sorts null based on + * the provided flag, working on Comparables. + *

When comparing two non-null objects, their Comparable implementation + * will be used: this means that non-null elements (that this Comparator + * will be applied to) need to implement Comparable. + *

As a convenience, you can use the default shared instances: + * NullSafeComparator.NULLS_LOW and + * NullSafeComparator.NULLS_HIGH. + * @param nullsLow whether to treat nulls lower or higher than non-null objects + * @see java.lang.Comparable + * @see #NULLS_LOW + * @see #NULLS_HIGH + */ + private NullSafeComparator(boolean nullsLow) { + this(new ComparableComparator(), nullsLow); + } + + /** + * Create a NullSafeComparator that sorts null based on the + * provided flag, decorating the given Comparator. + *

When comparing two non-null objects, the specified Comparator will be used. + * The given underlying Comparator must be able to handle the elements that this + * Comparator will be applied to. + * @param comparator the comparator to use when comparing two non-null objects + * @param nullsLow whether to treat nulls lower or higher than non-null objects + */ + public NullSafeComparator(Comparator comparator, boolean nullsLow) { + Assert.notNull(comparator, "The non-null comparator is required"); + this.nonNullComparator = comparator; + this.nullsLow = nullsLow; + } + + + public int compare(Object o1, Object o2) { + if (o1 == o2) { + return 0; + } + if (o1 == null) { + return (this.nullsLow ? -1 : 1); + } + if (o2 == null) { + return (this.nullsLow ? 1 : -1); + } + return this.nonNullComparator.compare(o1, o2); + } + + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof NullSafeComparator)) { + return false; + } + NullSafeComparator other = (NullSafeComparator) obj; + return (this.nonNullComparator.equals(other.nonNullComparator) && this.nullsLow == other.nullsLow); + } + + public int hashCode() { + return (this.nullsLow ? -1 : 1) * this.nonNullComparator.hashCode(); + } + + public String toString() { + return "NullSafeComparator: non-null comparator [" + this.nonNullComparator + "]; " + + (this.nullsLow ? "nulls low" : "nulls high"); + } + +} Index: 3rdParty_sources/spring/org/springframework/util/comparator/package.html =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/util/comparator/package.html,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/util/comparator/package.html 17 Aug 2012 15:16:04 -0000 1.1 @@ -0,0 +1,8 @@ + + + +Useful generic java.util.Comparator implementations, +such as an invertible comparator and a compound comparator. + + + Index: 3rdParty_sources/spring/org/springframework/util/xml/DomUtils.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/util/xml/DomUtils.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/util/xml/DomUtils.java 17 Aug 2012 15:16:05 -0000 1.1 @@ -0,0 +1,167 @@ +/* + * 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.util.xml; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; + +import org.w3c.dom.CharacterData; +import org.w3c.dom.Comment; +import org.w3c.dom.Element; +import org.w3c.dom.EntityReference; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +import org.springframework.util.Assert; + +/** + * Convenience methods for working with the DOM API, + * in particular for working with DOM Nodes and DOM Elements. + * + * @author Juergen Hoeller + * @author Rob Harrop + * @author Costin Leau + * @since 1.2 + * @see org.w3c.dom.Node + * @see org.w3c.dom.Element + */ +public abstract class DomUtils { + + /** + * Retrieve all child elements of the given DOM element that match any of + * the given element names. Only look at the direct child level of the + * given element; do not go into further depth (in contrast to the + * DOM API's getElementsByTagName method). + * @param ele the DOM element to analyze + * @param childEleNames the child element names to look for + * @return a List of child org.w3c.dom.Element instances + * @see org.w3c.dom.Element + * @see org.w3c.dom.Element#getElementsByTagName + */ + public static List getChildElementsByTagName(Element ele, String[] childEleNames) { + Assert.notNull(ele, "Element must not be null"); + Assert.notNull(childEleNames, "Element names collection must not be null"); + List childEleNameList = Arrays.asList(childEleNames); + NodeList nl = ele.getChildNodes(); + List childEles = new ArrayList(); + for (int i = 0; i < nl.getLength(); i++) { + Node node = nl.item(i); + if (node instanceof Element && nodeNameMatch(node, childEleNameList)) { + childEles.add(node); + } + } + return childEles; + } + + /** + * Retrieve all child elements of the given DOM element that match + * the given element name. Only look at the direct child level of the + * given element; do not go into further depth (in contrast to the + * DOM API's getElementsByTagName method). + * @param ele the DOM element to analyze + * @param childEleName the child element name to look for + * @return a List of child org.w3c.dom.Element instances + * @see org.w3c.dom.Element + * @see org.w3c.dom.Element#getElementsByTagName + */ + public static List getChildElementsByTagName(Element ele, String childEleName) { + return getChildElementsByTagName(ele, new String[] {childEleName}); + } + + /** + * Utility method that returns the first child element + * identified by its name. + * @param ele the DOM element to analyze + * @param childEleName the child element name to look for + * @return the org.w3c.dom.Element instance, + * or null if none found + */ + public static Element getChildElementByTagName(Element ele, String childEleName) { + Assert.notNull(ele, "Element must not be null"); + Assert.notNull(childEleName, "Element name must not be null"); + NodeList nl = ele.getChildNodes(); + for (int i = 0; i < nl.getLength(); i++) { + Node node = nl.item(i); + if (node instanceof Element && nodeNameMatch(node, childEleName)) { + return (Element) node; + } + } + return null; + } + + /** + * Utility method that returns the first child element value + * identified by its name. + * @param ele the DOM element to analyze + * @param childEleName the child element name to look for + * @return the extracted text value, + * or null if no child element found + */ + public static String getChildElementValueByTagName(Element ele, String childEleName) { + Element child = getChildElementByTagName(ele, childEleName); + return (child != null ? getTextValue(child) : null); + } + + /** + * Extract the text value from the given DOM element, ignoring XML comments. + *

Appends all CharacterData nodes and EntityReference nodes + * into a single String value, excluding Comment nodes. + * @see CharacterData + * @see EntityReference + * @see Comment + */ + public static String getTextValue(Element valueEle) { + Assert.notNull(valueEle, "Element must not be null"); + StringBuffer value = new StringBuffer(); + NodeList nl = valueEle.getChildNodes(); + for (int i = 0; i < nl.getLength(); i++) { + Node item = nl.item(i); + if ((item instanceof CharacterData && !(item instanceof Comment)) || item instanceof EntityReference) { + value.append(item.getNodeValue()); + } + } + return value.toString(); + } + + /** + * Namespace-aware equals comparison. Returns true if either + * {@link Node#getLocalName} or {@link Node#getNodeName} equals desiredName, + * otherwise returns false. + */ + public static boolean nodeNameEquals(Node node, String desiredName) { + Assert.notNull(node, "Node must not be null"); + Assert.notNull(desiredName, "Desired name must not be null"); + return nodeNameMatch(node, desiredName); + } + + /** + * Matches the given node's name and local name against the given desired name. + */ + private static boolean nodeNameMatch(Node node, String desiredName) { + return (desiredName.equals(node.getNodeName()) || desiredName.equals(node.getLocalName())); + } + + /** + * Matches the given node's name and local name against the given desired names. + */ + private static boolean nodeNameMatch(Node node, Collection desiredNames) { + return (desiredNames.contains(node.getNodeName()) || desiredNames.contains(node.getLocalName())); + } + +} Index: 3rdParty_sources/spring/org/springframework/util/xml/SimpleSaxErrorHandler.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/util/xml/SimpleSaxErrorHandler.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/util/xml/SimpleSaxErrorHandler.java 17 Aug 2012 15:16:05 -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.util.xml; + +import org.apache.commons.logging.Log; +import org.xml.sax.ErrorHandler; +import org.xml.sax.SAXException; +import org.xml.sax.SAXParseException; + +/** + * Simple org.xml.sax.ErrorHandler implementation: + * logs warnings using the given Commons Logging logger instance, + * and rethrows errors to discontinue the XML transformation. + * + * @author Juergen Hoeller + * @since 1.2 + */ +public class SimpleSaxErrorHandler implements ErrorHandler { + + private final Log logger; + + + /** + * Create a new SimpleSaxErrorHandler for the given + * Commons Logging logger instance. + */ + public SimpleSaxErrorHandler(Log logger) { + this.logger = logger; + } + + + public void warning(SAXParseException ex) throws SAXException { + logger.warn("Ignored XML validation warning", ex); + } + + public void error(SAXParseException ex) throws SAXException { + throw ex; + } + + public void fatalError(SAXParseException ex) throws SAXException { + throw ex; + } + +} Index: 3rdParty_sources/spring/org/springframework/util/xml/SimpleTransformErrorListener.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/util/xml/SimpleTransformErrorListener.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/util/xml/SimpleTransformErrorListener.java 17 Aug 2012 15:16:05 -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.util.xml; + +import javax.xml.transform.ErrorListener; +import javax.xml.transform.TransformerException; + +import org.apache.commons.logging.Log; + +/** + * Simple javax.xml.transform.ErrorListener implementation: + * logs warnings using the given Commons Logging logger instance, + * and rethrows errors to discontinue the XML transformation. + * + * @author Juergen Hoeller + * @since 1.2 + */ +public class SimpleTransformErrorListener implements ErrorListener { + + private final Log logger; + + + /** + * Create a new SimpleTransformErrorListener for the given + * Commons Logging logger instance. + */ + public SimpleTransformErrorListener(Log logger) { + this.logger = logger; + } + + + public void warning(TransformerException ex) throws TransformerException { + logger.warn("XSLT transformation warning", ex); + } + + public void error(TransformerException ex) throws TransformerException { + logger.error("XSLT transformation error", ex); + } + + public void fatalError(TransformerException ex) throws TransformerException { + throw ex; + } + +} Index: 3rdParty_sources/spring/org/springframework/util/xml/TransformerUtils.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/util/xml/TransformerUtils.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/util/xml/TransformerUtils.java 17 Aug 2012 15:16:05 -0000 1.1 @@ -0,0 +1,86 @@ +/* + * 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.util.xml; + +import javax.xml.transform.OutputKeys; +import javax.xml.transform.Transformer; + +import org.springframework.util.Assert; + +/** + * Contains common behavior relating to {@link javax.xml.transform.Transformer Transformers}. + * + * @author Rick Evans + * @author Juergen Hoeller + * @since 2.5.5 + */ +public abstract class TransformerUtils { + + /** + * The indent amount of characters if + * {@link #enableIndenting(javax.xml.transform.Transformer) indenting is enabled}. + *

Defaults to "2". + */ + public static final int DEFAULT_INDENT_AMOUNT = 2; + + + /** + * Enable indenting for the supplied {@link javax.xml.transform.Transformer}. + *

If the underlying XSLT engine is Xalan, then the special output + * key indent-amount will be also be set to a value + * of {@link #DEFAULT_INDENT_AMOUNT} characters. + * @param transformer the target transformer + * @see javax.xml.transform.Transformer#setOutputProperty(String, String) + * @see javax.xml.transform.OutputKeys#INDENT + */ + public static void enableIndenting(Transformer transformer) { + enableIndenting(transformer, DEFAULT_INDENT_AMOUNT); + } + + /** + * Enable indenting for the supplied {@link javax.xml.transform.Transformer}. + *

If the underlying XSLT engine is Xalan, then the special output + * key indent-amount will be also be set to a value + * of {@link #DEFAULT_INDENT_AMOUNT} characters. + * @param transformer the target transformer + * @param indentAmount the size of the indent (2 characters, 3 characters, etc.) + * @see javax.xml.transform.Transformer#setOutputProperty(String, String) + * @see javax.xml.transform.OutputKeys#INDENT + */ + public static void enableIndenting(Transformer transformer, int indentAmount) { + Assert.notNull(transformer, "Transformer must not be null"); + Assert.isTrue(indentAmount > -1, "The indent amount cannot be less than zero : got " + indentAmount); + transformer.setOutputProperty(OutputKeys.INDENT, "yes"); + try { + // Xalan-specific, but this is the most common XSLT engine in any case + transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", String.valueOf(indentAmount)); + } + catch (IllegalArgumentException ignored) { + } + } + + /** + * Disable indenting for the supplied {@link javax.xml.transform.Transformer}. + * @param transformer the target transformer + * @see javax.xml.transform.OutputKeys#INDENT + */ + public static void disableIndenting(Transformer transformer) { + Assert.notNull(transformer, "Transformer must not be null"); + transformer.setOutputProperty(OutputKeys.INDENT, "no"); + } + +} Index: 3rdParty_sources/spring/org/springframework/util/xml/XmlValidationModeDetector.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/util/xml/XmlValidationModeDetector.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/util/xml/XmlValidationModeDetector.java 17 Aug 2012 15:16:05 -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.util.xml; + +import java.io.BufferedReader; +import java.io.CharConversionException; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; + +import org.springframework.util.StringUtils; + +/** + * Detects whether an XML stream is using DTD- or XSD-based validation. + * + * @author Rob Harrop + * @author Juergen Hoeller + * @since 2.0 + */ +public class XmlValidationModeDetector { + + /** + * Indicates that the validation should be disabled. + */ + public static final int VALIDATION_NONE = 0; + + /** + * Indicates that the validation mode should be auto-guessed, since we cannot find + * a clear indication (probably choked on some special characters, or the like). + */ + public static final int VALIDATION_AUTO = 1; + + /** + * Indicates that DTD validation should be used (we found a "DOCTYPE" declaration). + */ + public static final int VALIDATION_DTD = 2; + + /** + * Indicates that XSD validation should be used (found no "DOCTYPE" declaration). + */ + public static final int VALIDATION_XSD = 3; + + + /** + * The token in a XML document that declares the DTD to use for validation + * and thus that DTD validation is being used. + */ + private static final String DOCTYPE = "DOCTYPE"; + + /** + * The token that indicates the start of an XML comment. + */ + private static final String START_COMMENT = ""; + + + /** + * Indicates whether or not the current parse position is inside an XML comment. + */ + private boolean inComment; + + + /** + * Detect the validation mode for the XML document in the supplied {@link InputStream}. + * Note that the supplied {@link InputStream} is closed by this method before returning. + * @param inputStream the InputStream to parse + * @throws IOException in case of I/O failure + * @see #VALIDATION_DTD + * @see #VALIDATION_XSD + */ + public int detectValidationMode(InputStream inputStream) throws IOException { + // Peek into the file to look for DOCTYPE. + BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream)); + try { + boolean isDtdValidated = false; + String content; + while ((content = reader.readLine()) != null) { + content = consumeCommentTokens(content); + if (this.inComment || !StringUtils.hasText(content)) { + continue; + } + if (hasDoctype(content)) { + isDtdValidated = true; + break; + } + if (hasOpeningTag(content)) { + // End of meaningful data... + break; + } + } + return (isDtdValidated ? VALIDATION_DTD : VALIDATION_XSD); + } + catch (CharConversionException ex) { + // Choked on some character encoding... + // Leave the decision up to the caller. + return VALIDATION_AUTO; + } + finally { + reader.close(); + } + } + + + /** + * Does the content contain the the DTD DOCTYPE declaration? + */ + private boolean hasDoctype(String content) { + return (content.indexOf(DOCTYPE) > -1); + } + + /** + * Does the supplied content contain an XML opening tag. If the parse state is currently + * in an XML comment then this method always returns false. It is expected that all comment + * tokens will have consumed for the supplied content before passing the remainder to this method. + */ + private boolean hasOpeningTag(String content) { + if (this.inComment) { + return false; + } + int openTagIndex = content.indexOf('<'); + return (openTagIndex > -1 && content.length() > openTagIndex && Character.isLetter(content.charAt(openTagIndex + 1))); + } + + /** + * Consumes all the leading comment data in the given String and returns the remaining content, which + * may be empty since the supplied content might be all comment data. For our purposes it is only important + * to strip leading comment content on a line since the first piece of non comment content will be either + * the DOCTYPE declaration or the root element of the document. + */ + private String consumeCommentTokens(String line) { + if (line.indexOf(START_COMMENT) == -1 && line.indexOf(END_COMMENT) == -1) { + return line; + } + while ((line = consume(line)) != null) { + if (!this.inComment && !line.trim().startsWith(START_COMMENT)) { + return line; + } + } + return line; + } + + /** + * Consume the next comment token, update the "inComment" flag + * and return the remaining content. + */ + private String consume(String line) { + int index = (this.inComment ? endComment(line) : startComment(line)); + return (index == -1 ? null : line.substring(index)); + } + + /** + * Try to consume the {@link #START_COMMENT} token. + * @see #commentToken(String, String, boolean) + */ + private int startComment(String line) { + return commentToken(line, START_COMMENT, true); + } + + private int endComment(String line) { + return commentToken(line, END_COMMENT, false); + } + + /** + * Try to consume the supplied token against the supplied content and update the + * in comment parse state to the supplied value. Returns the index into the content + * which is after the token or -1 if the token is not found. + */ + private int commentToken(String line, String token, boolean inCommentIfPresent) { + int index = line.indexOf(token); + if (index > - 1) { + this.inComment = inCommentIfPresent; + } + return (index == -1 ? index : index + token.length()); + } + +} Index: 3rdParty_sources/spring/org/springframework/util/xml/package.html =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/util/xml/package.html,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/util/xml/package.html 17 Aug 2012 15:16:05 -0000 1.1 @@ -0,0 +1,8 @@ + + + +Miscellaneous utility classes for XML parsing and transformation, +such as error handlers that log warnings via Commons Logging. + + + Index: 3rdParty_sources/spring/org/springframework/validation/AbstractBindingResult.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/validation/AbstractBindingResult.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/validation/AbstractBindingResult.java 17 Aug 2012 15:16:04 -0000 1.1 @@ -0,0 +1,378 @@ +/* + * 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.validation; + +import java.beans.PropertyEditor; +import java.io.Serializable; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.springframework.beans.PropertyEditorRegistry; +import org.springframework.util.StringUtils; + +/** + * Abstract implementation of the {@link BindingResult} interface and + * its super-interface {@link Errors}. Encapsulates common management of + * {@link ObjectError ObjectErrors} and {@link FieldError FieldErrors}. + * + * @author Juergen Hoeller + * @author Rob Harrop + * @since 2.0 + * @see Errors + */ +public abstract class AbstractBindingResult extends AbstractErrors implements BindingResult, Serializable { + + private final String objectName; + + private MessageCodesResolver messageCodesResolver = new DefaultMessageCodesResolver(); + + private final List errors = new LinkedList(); + + private final Set suppressedFields = new HashSet(); + + + /** + * Create a new AbstractBindingResult instance. + * @param objectName the name of the target object + * @see DefaultMessageCodesResolver + */ + protected AbstractBindingResult(String objectName) { + this.objectName = objectName; + } + + /** + * Set the strategy to use for resolving errors into message codes. + * Default is DefaultMessageCodesResolver. + * @see DefaultMessageCodesResolver + */ + public void setMessageCodesResolver(MessageCodesResolver messageCodesResolver) { + this.messageCodesResolver = messageCodesResolver; + } + + /** + * Return the strategy to use for resolving errors into message codes. + */ + public MessageCodesResolver getMessageCodesResolver() { + return this.messageCodesResolver; + } + + + //--------------------------------------------------------------------- + // Implementation of the Errors interface + //--------------------------------------------------------------------- + + public String getObjectName() { + return this.objectName; + } + + + public void reject(String errorCode, Object[] errorArgs, String defaultMessage) { + addError(new ObjectError(getObjectName(), resolveMessageCodes(errorCode), errorArgs, defaultMessage)); + } + + public void rejectValue(String field, String errorCode, Object[] errorArgs, String defaultMessage) { + if ("".equals(getNestedPath()) && !StringUtils.hasLength(field)) { + // We're at the top of the nested object hierarchy, + // so the present level is not a field but rather the top object. + // The best we can do is register a global error here... + reject(errorCode, errorArgs, defaultMessage); + return; + } + String fixedField = fixedField(field); + Object newVal = getActualFieldValue(fixedField); + FieldError fe = new FieldError( + getObjectName(), fixedField, newVal, false, + resolveMessageCodes(errorCode, field), errorArgs, defaultMessage); + addError(fe); + } + + public void addError(ObjectError error) { + this.errors.add(error); + } + + public void addAllErrors(Errors errors) { + if (!errors.getObjectName().equals(getObjectName())) { + throw new IllegalArgumentException("Errors object needs to have same object name"); + } + this.errors.addAll(errors.getAllErrors()); + } + + /** + * Resolve the given error code into message codes. + * Calls the MessageCodesResolver with appropriate parameters. + * @param errorCode the error code to resolve into message codes + * @return the resolved message codes + * @see #setMessageCodesResolver + */ + public String[] resolveMessageCodes(String errorCode) { + return getMessageCodesResolver().resolveMessageCodes(errorCode, getObjectName()); + } + + public String[] resolveMessageCodes(String errorCode, String field) { + String fixedField = fixedField(field); + Class fieldType = getFieldType(fixedField); + return getMessageCodesResolver().resolveMessageCodes(errorCode, getObjectName(), fixedField, fieldType); + } + + + public boolean hasErrors() { + return !this.errors.isEmpty(); + } + + public int getErrorCount() { + return this.errors.size(); + } + + public List getAllErrors() { + return Collections.unmodifiableList(this.errors); + } + + public List getGlobalErrors() { + List result = new LinkedList(); + for (Iterator it = this.errors.iterator(); it.hasNext();) { + Object error = it.next(); + if (!(error instanceof FieldError)) { + result.add(error); + } + } + return Collections.unmodifiableList(result); + } + + public ObjectError getGlobalError() { + for (Iterator it = this.errors.iterator(); it.hasNext();) { + ObjectError objectError = (ObjectError) it.next(); + if (!(objectError instanceof FieldError)) { + return objectError; + } + } + return null; + } + + public List getFieldErrors() { + List result = new LinkedList(); + for (Iterator it = this.errors.iterator(); it.hasNext();) { + Object error = it.next(); + if (error instanceof FieldError) { + result.add(error); + } + } + return Collections.unmodifiableList(result); + } + + public FieldError getFieldError() { + for (Iterator it = this.errors.iterator(); it.hasNext();) { + Object error = it.next(); + if (error instanceof FieldError) { + return (FieldError) error; + } + } + return null; + } + + public List getFieldErrors(String field) { + List result = new LinkedList(); + String fixedField = fixedField(field); + for (Iterator it = this.errors.iterator(); it.hasNext();) { + Object error = it.next(); + if (error instanceof FieldError && isMatchingFieldError(fixedField, (FieldError) error)) { + result.add(error); + } + } + return Collections.unmodifiableList(result); + } + + public FieldError getFieldError(String field) { + String fixedField = fixedField(field); + for (Iterator it = this.errors.iterator(); it.hasNext();) { + Object error = it.next(); + if (error instanceof FieldError) { + FieldError fe = (FieldError) error; + if (isMatchingFieldError(fixedField, fe)) { + return fe; + } + } + } + return null; + } + + public Object getFieldValue(String field) { + FieldError fe = getFieldError(field); + // Use rejected value in case of error, current bean property value else. + Object value = null; + if (fe != null) { + value = fe.getRejectedValue(); + } + else { + value = getActualFieldValue(fixedField(field)); + } + // Apply formatting, but not on binding failures like type mismatches. + if (fe == null || !fe.isBindingFailure()) { + value = formatFieldValue(field, value); + } + return value; + } + + /** + * This default implementation determines the type based on the actual + * field value, if any. Subclasses should override this to determine + * the type from a descriptor, even for null values. + * @see #getActualFieldValue + */ + public Class getFieldType(String field) { + Object value = getActualFieldValue(fixedField(field)); + if (value != null) { + return value.getClass(); + } + return null; + } + + + //--------------------------------------------------------------------- + // Implementation of BindingResult interface + //--------------------------------------------------------------------- + + /** + * Return a model Map for the obtained state, exposing an Errors + * instance as '{@link #MODEL_KEY_PREFIX MODEL_KEY_PREFIX} + objectName' + * and the object itself. + *

Note that the Map is constructed every time you're calling this method. + * Adding things to the map and then re-calling this method will not work. + *

The attributes in the model Map returned by this method are usually + * included in the ModelAndView for a form view that uses Spring's bind tag, + * which needs access to the Errors instance. Spring's SimpleFormController + * will do this for you when rendering its form or success view. When + * building the ModelAndView yourself, you need to include the attributes + * from the model Map returned by this method yourself. + * @see #getObjectName + * @see #MODEL_KEY_PREFIX + * @see org.springframework.web.servlet.ModelAndView + * @see org.springframework.web.servlet.tags.BindTag + * @see org.springframework.web.servlet.mvc.SimpleFormController + */ + public Map getModel() { + Map model = new HashMap(2); + // Errors instance, even if no errors. + model.put(MODEL_KEY_PREFIX + getObjectName(), this); + // Mapping from name to target object. + model.put(getObjectName(), getTarget()); + return model; + } + + public Object getRawFieldValue(String field) { + return getActualFieldValue(fixedField(field)); + } + + /** + * This implementation delegates to the + * {@link #getPropertyEditorRegistry() PropertyEditorRegistry}'s + * editor lookup facility, if available. + */ + public PropertyEditor findEditor(String field, Class valueType) { + PropertyEditorRegistry editorRegistry = getPropertyEditorRegistry(); + if (editorRegistry != null) { + Class valueTypeToUse = valueType; + if (valueTypeToUse == null) { + valueTypeToUse = getFieldType(field); + } + return editorRegistry.findCustomEditor(valueTypeToUse, fixedField(field)); + } + else { + return null; + } + } + + /** + * This implementation returns null. + */ + public PropertyEditorRegistry getPropertyEditorRegistry() { + return null; + } + + /** + * Mark the specified disallowed field as suppressed. + *

The data binder invokes this for each field value that was + * detected to target a disallowed field. + * @see DataBinder#setAllowedFields + */ + public void recordSuppressedField(String field) { + this.suppressedFields.add(field); + } + + /** + * Return the list of fields that were suppressed during the bind process. + *

Can be used to determine whether any field values were targetting + * disallowed fields. + * @see DataBinder#setAllowedFields + */ + public String[] getSuppressedFields() { + return StringUtils.toStringArray(this.suppressedFields); + } + + + public boolean equals(Object other) { + if (this == other) { + return true; + } + if (!(other instanceof BindingResult)) { + return false; + } + BindingResult otherResult = (BindingResult) other; + return (getObjectName().equals(otherResult.getObjectName()) && + getTarget().equals(otherResult.getTarget()) && + getAllErrors().equals(otherResult.getAllErrors())); + } + + public int hashCode() { + return getObjectName().hashCode() * 29 + getTarget().hashCode(); + } + + + //--------------------------------------------------------------------- + // Template methods to be implemented/overridden by subclasses + //--------------------------------------------------------------------- + + /** + * Return the wrapped target object. + */ + public abstract Object getTarget(); + + /** + * Extract the actual field value for the given field. + * @param field the field to check + * @return the current value of the field + */ + protected abstract Object getActualFieldValue(String field); + + /** + * Format the given value for the specified field. + *

The default implementation simply returns the field value as-is. + * @param field the field to check + * @param value the value of the field (either a rejected value + * other than from a binding error, or an actual field value) + * @return the formatted value + */ + protected Object formatFieldValue(String field, Object value) { + return value; + } + +} Index: 3rdParty_sources/spring/org/springframework/validation/AbstractErrors.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/validation/AbstractErrors.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/validation/AbstractErrors.java 17 Aug 2012 15:16:04 -0000 1.1 @@ -0,0 +1,223 @@ +/* + * 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.validation; + +import java.io.Serializable; +import java.util.Collections; +import java.util.EmptyStackException; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Stack; + +import org.springframework.util.StringUtils; + +/** + * Abstract implementation of the {@link Errors} interface. Provides common + * access to evaluated errors; however, does not define concrete management + * of {@link ObjectError ObjectErrors} and {@link FieldError FieldErrors}. + * + * @author Juergen Hoeller + * @since 2.5.3 + */ +public abstract class AbstractErrors implements Errors, Serializable { + + private String nestedPath = ""; + + private final Stack nestedPathStack = new Stack(); + + + public void setNestedPath(String nestedPath) { + doSetNestedPath(nestedPath); + this.nestedPathStack.clear(); + } + + public String getNestedPath() { + return this.nestedPath; + } + + public void pushNestedPath(String subPath) { + this.nestedPathStack.push(getNestedPath()); + doSetNestedPath(getNestedPath() + subPath); + } + + public void popNestedPath() throws IllegalArgumentException { + try { + String formerNestedPath = (String) this.nestedPathStack.pop(); + doSetNestedPath(formerNestedPath); + } + catch (EmptyStackException ex) { + throw new IllegalStateException("Cannot pop nested path: no nested path on stack"); + } + } + + /** + * Actually set the nested path. + * Delegated to by setNestedPath and pushNestedPath. + */ + protected void doSetNestedPath(String nestedPath) { + if (nestedPath == null) { + nestedPath = ""; + } + nestedPath = canonicalFieldName(nestedPath); + if (nestedPath.length() > 0 && !nestedPath.endsWith(Errors.NESTED_PATH_SEPARATOR)) { + nestedPath += Errors.NESTED_PATH_SEPARATOR; + } + this.nestedPath = nestedPath; + } + + /** + * Transform the given field into its full path, + * regarding the nested path of this instance. + */ + protected String fixedField(String field) { + if (StringUtils.hasLength(field)) { + return getNestedPath() + canonicalFieldName(field); + } + else { + String path = getNestedPath(); + return (path.endsWith(Errors.NESTED_PATH_SEPARATOR) ? + path.substring(0, path.length() - NESTED_PATH_SEPARATOR.length()) : path); + } + } + + /** + * Determine the canonical field name for the given field. + *

The default implementation simply returns the field name as-is. + * @param field the original field name + * @return the canonical field name + */ + protected String canonicalFieldName(String field) { + return field; + } + + + public void reject(String errorCode) { + reject(errorCode, null, null); + } + + public void reject(String errorCode, String defaultMessage) { + reject(errorCode, null, defaultMessage); + } + + public void rejectValue(String field, String errorCode) { + rejectValue(field, errorCode, null, null); + } + + public void rejectValue(String field, String errorCode, String defaultMessage) { + rejectValue(field, errorCode, null, defaultMessage); + } + + + public boolean hasErrors() { + return !getAllErrors().isEmpty(); + } + + public int getErrorCount() { + return getAllErrors().size(); + } + + public List getAllErrors() { + List result = new LinkedList(); + result.addAll(getGlobalErrors()); + result.addAll(getFieldErrors()); + return Collections.unmodifiableList(result); + } + + public boolean hasGlobalErrors() { + return (getGlobalErrorCount() > 0); + } + + public int getGlobalErrorCount() { + return getGlobalErrors().size(); + } + + public ObjectError getGlobalError() { + List globalErrors = getGlobalErrors(); + return (!globalErrors.isEmpty() ? (ObjectError) globalErrors.get(0) : null); + } + + public boolean hasFieldErrors() { + return (getFieldErrorCount() > 0); + } + + public int getFieldErrorCount() { + return getFieldErrors().size(); + } + + public FieldError getFieldError() { + List fieldErrors = getFieldErrors(); + return (!fieldErrors.isEmpty() ? (FieldError) fieldErrors.get(0) : null); + } + + public boolean hasFieldErrors(String field) { + return (getFieldErrorCount(field) > 0); + } + + public int getFieldErrorCount(String field) { + return getFieldErrors(field).size(); + } + + public List getFieldErrors(String field) { + List fieldErrors = getFieldErrors(); + List result = new LinkedList(); + String fixedField = fixedField(field); + for (Iterator it = fieldErrors.iterator(); it.hasNext();) { + Object error = it.next(); + if (isMatchingFieldError(fixedField, (FieldError) error)) { + result.add(error); + } + } + return Collections.unmodifiableList(result); + } + + public FieldError getFieldError(String field) { + List fieldErrors = getFieldErrors(field); + return (!fieldErrors.isEmpty() ? (FieldError) fieldErrors.get(0) : null); + } + + + public Class getFieldType(String field) { + Object value = getFieldValue(field); + if (value != null) { + return value.getClass(); + } + return null; + } + /** + * Check whether the given FieldError matches the given field. + * @param field the field that we are looking up FieldErrors for + * @param fieldError the candidate FieldError + * @return whether the FieldError matches the given field + */ + protected boolean isMatchingFieldError(String field, FieldError fieldError) { + return (field.equals(fieldError.getField()) || + (field.endsWith("*") && fieldError.getField().startsWith(field.substring(0, field.length() - 1)))); + } + + + public String toString() { + StringBuffer sb = new StringBuffer(getClass().getName()); + sb.append(": ").append(getErrorCount()).append(" errors"); + Iterator it = getAllErrors().iterator(); + while (it.hasNext()) { + sb.append('\n').append(it.next()); + } + return sb.toString(); + } + +} Index: 3rdParty_sources/spring/org/springframework/validation/AbstractPropertyBindingResult.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/validation/AbstractPropertyBindingResult.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/validation/AbstractPropertyBindingResult.java 17 Aug 2012 15:16:04 -0000 1.1 @@ -0,0 +1,127 @@ +/* + * 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.validation; + +import java.beans.PropertyEditor; + +import org.springframework.beans.BeanUtils; +import org.springframework.beans.ConfigurablePropertyAccessor; +import org.springframework.beans.PropertyAccessorUtils; +import org.springframework.beans.PropertyEditorRegistry; + +/** + * Abstract base class for {@link BindingResult} implementations that work with + * Spring's {@link org.springframework.beans.PropertyAccessor} mechanism. + * Pre-implements field access through delegation to the corresponding + * PropertyAccessor methods. + * + * @author Juergen Hoeller + * @since 2.0 + * @see #getPropertyAccessor() + * @see org.springframework.beans.PropertyAccessor + * @see org.springframework.beans.ConfigurablePropertyAccessor + */ +public abstract class AbstractPropertyBindingResult extends AbstractBindingResult { + + /** + * Create a new AbstractPropertyBindingResult instance. + * @param objectName the name of the target object + * @see DefaultMessageCodesResolver + */ + protected AbstractPropertyBindingResult(String objectName) { + super(objectName); + } + + + /** + * Returns the underlying PropertyAccessor. + * @see #getPropertyAccessor() + */ + public PropertyEditorRegistry getPropertyEditorRegistry() { + return getPropertyAccessor(); + } + + /** + * Returns the canonical property name. + * @see org.springframework.beans.PropertyAccessorUtils#canonicalPropertyName + */ + protected String canonicalFieldName(String field) { + return PropertyAccessorUtils.canonicalPropertyName(field); + } + + /** + * Determines the field type from the property type. + * @see #getPropertyAccessor() + */ + public Class getFieldType(String field) { + return getPropertyAccessor().getPropertyType(fixedField(field)); + } + + /** + * Fetches the field value from the PropertyAccessor. + * @see #getPropertyAccessor() + */ + protected Object getActualFieldValue(String field) { + return getPropertyAccessor().getPropertyValue(field); + } + + /** + * Formats the field value based on registered PropertyEditors. + * @see #getCustomEditor + */ + protected Object formatFieldValue(String field, Object value) { + PropertyEditor customEditor = getCustomEditor(field); + if (customEditor != null) { + customEditor.setValue(value); + String textValue = customEditor.getAsText(); + // If the PropertyEditor returned null, there is no appropriate + // text representation for this value: only use it if non-null. + if (textValue != null) { + return textValue; + } + } + return value; + } + + /** + * Retrieve the custom PropertyEditor for the given field, if any. + * @param field the field name + * @return the custom PropertyEditor, or null + */ + protected PropertyEditor getCustomEditor(String field) { + String fixedField = fixedField(field); + Class targetType = getPropertyAccessor().getPropertyType(fixedField); + PropertyEditor editor = getPropertyAccessor().findCustomEditor(targetType, fixedField); + if (editor == null) { + editor = BeanUtils.findEditorByConvention(targetType); + } + return editor; + } + + + /** + * Provide the PropertyAccessor to work with, according to the + * concrete strategy of access. + *

Note that a PropertyAccessor used by a BindingResult should + * always have its "extractOldValueForEditor" flag set to "true" + * by default, since this is typically possible without side effects + * for model objects that serve as data binding target. + * @see ConfigurablePropertyAccessor#setExtractOldValueForEditor + */ + public abstract ConfigurablePropertyAccessor getPropertyAccessor(); + +} Index: 3rdParty_sources/spring/org/springframework/validation/BeanPropertyBindingResult.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/validation/BeanPropertyBindingResult.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/validation/BeanPropertyBindingResult.java 17 Aug 2012 15:16:04 -0000 1.1 @@ -0,0 +1,87 @@ +/* + * 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.validation; + +import java.io.Serializable; + +import org.springframework.beans.BeanWrapper; +import org.springframework.beans.ConfigurablePropertyAccessor; +import org.springframework.beans.PropertyAccessorFactory; +import org.springframework.util.Assert; + +/** + * Default implementation of the {@link Errors} and {@link BindingResult} + * interfaces, for the registration and evaluation of binding errors on + * JavaBean objects. + * + *

Performs standard JavaBean property access, also supporting nested + * properties. Normally, application code will work with the + * Errors interface or the BindingResult interface. + * A {@link DataBinder} returns its BindingResult via + * {@link org.springframework.validation.DataBinder#getBindingResult()}. + * + * @author Juergen Hoeller + * @since 2.0 + * @see DataBinder#getBindingResult() + * @see DataBinder#initBeanPropertyAccess() + * @see DirectFieldBindingResult + */ +public class BeanPropertyBindingResult extends AbstractPropertyBindingResult implements Serializable { + + private final Object target; + + private transient BeanWrapper beanWrapper; + + + /** + * Creates a new instance of the {@link BeanPropertyBindingResult} class. + * @param target the target bean to bind onto + * @param objectName the name of the target object + */ + public BeanPropertyBindingResult(Object target, String objectName) { + super(objectName); + this.target = target; + } + + + public final Object getTarget() { + return this.target; + } + + /** + * Returns the {@link BeanWrapper} that this instance uses. + * Creates a new one if none existed before. + * @see #createBeanWrapper() + */ + public final ConfigurablePropertyAccessor getPropertyAccessor() { + if (this.beanWrapper == null) { + this.beanWrapper = createBeanWrapper(); + this.beanWrapper.setExtractOldValueForEditor(true); + } + return this.beanWrapper; + } + + /** + * Create a new {@link BeanWrapper} for the underlying target object. + * @see #getTarget() + */ + protected BeanWrapper createBeanWrapper() { + Assert.state(this.target != null, "Cannot access properties on null bean instance '" + getObjectName() + "'!"); + return PropertyAccessorFactory.forBeanPropertyAccess(this.target); + } + +} Index: 3rdParty_sources/spring/org/springframework/validation/BindException.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/validation/BindException.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/validation/BindException.java 17 Aug 2012 15:16:04 -0000 1.1 @@ -0,0 +1,258 @@ +/* + * 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.validation; + +import java.beans.PropertyEditor; +import java.util.List; +import java.util.Map; + +import org.springframework.beans.PropertyEditorRegistry; +import org.springframework.util.Assert; + +/** + * Thrown when binding errors are considered fatal. Implements the + * {@link BindingResult} interface (and its super-interface {@link Errors}) + * to allow for the direct analysis of binding errors. + * + *

As of Spring 2.0, this is a special-purpose class. Normally, + * application code will work with the {@link BindingResult} interface, + * or with a {@link DataBinder} that in turn exposes a BindingResult via + * {@link org.springframework.validation.DataBinder#getBindingResult()}. + * + * @author Rod Johnson + * @author Juergen Hoeller + * @author Rob Harrop + * @see BindingResult + * @see DataBinder#getBindingResult() + * @see DataBinder#close() + */ +public class BindException extends Exception implements BindingResult { + + /** + * Prefix for the name of the BindException instance in a model, + * followed by the object name. + * @deprecated in favor of BindingResult.MODEL_KEY_PREFIX + * @see BindingResult#MODEL_KEY_PREFIX + */ + public static final String ERROR_KEY_PREFIX = BindException.class.getName() + "."; + + + private final BindingResult bindingResult; + + + /** + * Create a new BindException instance for a BindingResult. + * @param bindingResult the BindingResult instance to wrap + */ + public BindException(BindingResult bindingResult) { + Assert.notNull(bindingResult, "BindingResult must not be null"); + this.bindingResult = bindingResult; + } + + /** + * Create a new BindException instance for a target bean. + * @param target target bean to bind onto + * @param objectName the name of the target object + * @see BeanPropertyBindingResult + */ + public BindException(Object target, String objectName) { + Assert.notNull(target, "Target object must not be null"); + this.bindingResult = new BeanPropertyBindingResult(target, objectName); + } + + + /** + * Return the BindingResult that this BindException wraps. + * Will typically be a BeanPropertyBindingResult. + * @see BeanPropertyBindingResult + */ + public final BindingResult getBindingResult() { + return this.bindingResult; + } + + + public String getObjectName() { + return this.bindingResult.getObjectName(); + } + + public void setNestedPath(String nestedPath) { + this.bindingResult.setNestedPath(nestedPath); + } + + public String getNestedPath() { + return this.bindingResult.getNestedPath(); + } + + public void pushNestedPath(String subPath) { + this.bindingResult.pushNestedPath(subPath); + } + + public void popNestedPath() throws IllegalStateException { + this.bindingResult.popNestedPath(); + } + + + public void reject(String errorCode) { + this.bindingResult.reject(errorCode); + } + + public void reject(String errorCode, String defaultMessage) { + this.bindingResult.reject(errorCode, defaultMessage); + } + + public void reject(String errorCode, Object[] errorArgs, String defaultMessage) { + this.bindingResult.reject(errorCode, errorArgs, defaultMessage); + } + + public void rejectValue(String field, String errorCode) { + this.bindingResult.rejectValue(field, errorCode); + } + + public void rejectValue(String field, String errorCode, String defaultMessage) { + this.bindingResult.rejectValue(field, errorCode, defaultMessage); + } + + public void rejectValue(String field, String errorCode, Object[] errorArgs, String defaultMessage) { + this.bindingResult.rejectValue(field, errorCode, errorArgs, defaultMessage); + } + + public void addAllErrors(Errors errors) { + this.bindingResult.addAllErrors(errors); + } + + + public boolean hasErrors() { + return this.bindingResult.hasErrors(); + } + + public int getErrorCount() { + return this.bindingResult.getErrorCount(); + } + + public List getAllErrors() { + return this.bindingResult.getAllErrors(); + } + + public boolean hasGlobalErrors() { + return this.bindingResult.hasGlobalErrors(); + } + + public int getGlobalErrorCount() { + return this.bindingResult.getGlobalErrorCount(); + } + + public List getGlobalErrors() { + return this.bindingResult.getGlobalErrors(); + } + + public ObjectError getGlobalError() { + return this.bindingResult.getGlobalError(); + } + + public boolean hasFieldErrors() { + return this.bindingResult.hasFieldErrors(); + } + + public int getFieldErrorCount() { + return this.bindingResult.getFieldErrorCount(); + } + + public List getFieldErrors() { + return this.bindingResult.getFieldErrors(); + } + + public FieldError getFieldError() { + return this.bindingResult.getFieldError(); + } + + public boolean hasFieldErrors(String field) { + return this.bindingResult.hasFieldErrors(field); + } + + public int getFieldErrorCount(String field) { + return this.bindingResult.getFieldErrorCount(field); + } + + public List getFieldErrors(String field) { + return this.bindingResult.getFieldErrors(field); + } + + public FieldError getFieldError(String field) { + return this.bindingResult.getFieldError(field); + } + + public Object getFieldValue(String field) { + return this.bindingResult.getFieldValue(field); + } + + public Class getFieldType(String field) { + return this.bindingResult.getFieldType(field); + } + + public Object getTarget() { + return this.bindingResult.getTarget(); + } + + public Map getModel() { + return this.bindingResult.getModel(); + } + + public Object getRawFieldValue(String field) { + return this.bindingResult.getRawFieldValue(field); + } + + public PropertyEditor findEditor(String field, Class valueType) { + return this.bindingResult.findEditor(field, valueType); + } + + public PropertyEditorRegistry getPropertyEditorRegistry() { + return this.bindingResult.getPropertyEditorRegistry(); + } + + public void addError(ObjectError error) { + this.bindingResult.addError(error); + } + + public String[] resolveMessageCodes(String errorCode, String field) { + return this.bindingResult.resolveMessageCodes(errorCode, field); + } + + public void recordSuppressedField(String field) { + this.bindingResult.recordSuppressedField(field); + } + + public String[] getSuppressedFields() { + return this.bindingResult.getSuppressedFields(); + } + + + /** + * Returns diagnostic information about the errors held in this object. + */ + public String getMessage() { + return this.bindingResult.toString(); + } + + public boolean equals(Object other) { + return (this == other || this.bindingResult.equals(other)); + } + + public int hashCode() { + return this.bindingResult.hashCode(); + } + +} Index: 3rdParty_sources/spring/org/springframework/validation/BindingErrorProcessor.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/validation/BindingErrorProcessor.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/validation/BindingErrorProcessor.java 17 Aug 2012 15:16:04 -0000 1.1 @@ -0,0 +1,77 @@ +/* + * 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.validation; + +import org.springframework.beans.PropertyAccessException; + +/** + * Strategy for processing DataBinder's missing field errors, + * and for translating a PropertyAccessException to a + * FieldError. + * + *

The error processor is pluggable so you can treat errors differently + * if you want to. A default implementation is provided for typical needs. + * + *

Note: As of Spring 2.0, this interface operates on a given BindingResult, + * to be compatible with any binding strategy (bean property, direct field access, etc). + * It can still receive a BindException as argument (since a BindException implements + * the BindingResult interface as well) but no longer operates on it directly. + * + * @author Alef Arendsen + * @author Juergen Hoeller + * @since 1.2 + * @see DataBinder#setBindingErrorProcessor + * @see DefaultBindingErrorProcessor + * @see BindingResult + * @see BindException + */ +public interface BindingErrorProcessor { + + /** + * Apply the missing field error to the given BindException. + *

Usually, a field error is created for a missing required field. + * @param missingField the field that was missing during binding + * @param bindingResult the errors object to add the error(s) to. + * You can add more than just one error or maybe even ignore it. + * The BindingResult object features convenience utils such as + * a resolveMessageCodes method to resolve an error code. + * @see BeanPropertyBindingResult#addError + * @see BeanPropertyBindingResult#resolveMessageCodes + */ + void processMissingFieldError(String missingField, BindingResult bindingResult); + + /** + * Translate the given PropertyAccessException to an appropriate + * error registered on the given Errors instance. + *

Note that two error types are available: FieldError and + * ObjectError. Usually, field errors are created, but in certain + * situations one might want to create a global ObjectError instead. + * @param ex the PropertyAccessException to translate + * @param bindingResult the errors object to add the error(s) to. + * You can add more than just one error or maybe even ignore it. + * The BindingResult object features convenience utils such as + * a resolveMessageCodes method to resolve an error code. + * @see Errors + * @see FieldError + * @see ObjectError + * @see MessageCodesResolver + * @see BeanPropertyBindingResult#addError + * @see BeanPropertyBindingResult#resolveMessageCodes + */ + void processPropertyAccessException(PropertyAccessException ex, BindingResult bindingResult); + +} Index: 3rdParty_sources/spring/org/springframework/validation/BindingResult.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/validation/BindingResult.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/validation/BindingResult.java 17 Aug 2012 15:16:04 -0000 1.1 @@ -0,0 +1,140 @@ +/* + * 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.validation; + +import java.beans.PropertyEditor; +import java.util.Map; + +import org.springframework.beans.PropertyEditorRegistry; + +/** + * General interface that represents binding results. Extends the + * {@link Errors interface} for error registration capabilities, + * allowing for a {@link Validator} to be applied, and adds + * binding-specific analysis and model building. + * + *

Serves as result holder for a {@link DataBinder}, obtained via + * the {@link DataBinder#getBindingResult()} method. BindingResult + * implementations can also be used directly, for example to invoke + * a {@link Validator} on it (e.g. as part of a unit test). + * + * @author Juergen Hoeller + * @since 2.0 + * @see DataBinder + * @see Errors + * @see Validator + * @see BeanPropertyBindingResult + * @see DirectFieldBindingResult + * @see MapBindingResult + */ +public interface BindingResult extends Errors { + + /** + * Prefix for the name of the BindingResult instance in a model, + * followed by the object name. + */ + String MODEL_KEY_PREFIX = BindingResult.class.getName() + "."; + + + /** + * Return the wrapped target object, which may be a bean, an object with + * public fields, a Map - depending on the concrete binding strategy. + */ + Object getTarget(); + + /** + * Return a model Map for the obtained state, exposing a BindingResult + * instance as '{@link #MODEL_KEY_PREFIX MODEL_KEY_PREFIX} + objectName' + * and the object itself as 'objectName'. + *

Note that the Map is constructed every time you're calling this method. + * Adding things to the map and then re-calling this method will not work. + *

The attributes in the model Map returned by this method are usually + * included in the {@link org.springframework.web.servlet.ModelAndView} + * for a form view that uses Spring's bind tag in a JSP, + * which needs access to the BindingResult instance. Spring's pre-built + * form controllers will do this for you when rendering a form view. + * When building the ModelAndView instance yourself, you need to include + * the attributes from the model Map returned by this method. + * @see #getObjectName() + * @see #MODEL_KEY_PREFIX + * @see org.springframework.web.servlet.ModelAndView + * @see org.springframework.web.servlet.tags.BindTag + * @see org.springframework.web.servlet.mvc.SimpleFormController + */ + Map getModel(); + + /** + * Extract the raw field value for the given field. + * Typically used for comparison purposes. + * @param field the field to check + * @return the current value of the field in its raw form, + * or null if not known + */ + Object getRawFieldValue(String field); + + /** + * Find a custom property editor for the given type and property. + * @param valueType the type of the property (can be null if a property + * is given but should be specified in any case for consistency checking) + * @param field the path of the property (name or nested path), or + * null if looking for an editor for all properties of the given type + * @return the registered editor, or null if none + */ + PropertyEditor findEditor(String field, Class valueType); + + /** + * Return the underlying PropertyEditorRegistry. + * @return the PropertyEditorRegistry, or null if none + * available for this BindingResult + */ + PropertyEditorRegistry getPropertyEditorRegistry(); + + /** + * Add a custom {@link ObjectError} or {@link FieldError} to the errors list. + *

Intended to be used by cooperating strategies such as {@link BindingErrorProcessor}. + * @see ObjectError + * @see FieldError + * @see BindingErrorProcessor + */ + void addError(ObjectError error); + + /** + * Resolve the given error code into message codes for the given field. + *

Calls the configured {@link MessageCodesResolver} with appropriate parameters. + * @param errorCode the error code to resolve into message codes + * @param field the field to resolve message codes for + * @return the resolved message codes + */ + String[] resolveMessageCodes(String errorCode, String field); + + /** + * Mark the specified disallowed field as suppressed. + *

The data binder invokes this for each field value that was + * detected to target a disallowed field. + * @see DataBinder#setAllowedFields + */ + void recordSuppressedField(String field); + + /** + * Return the list of fields that were suppressed during the bind process. + *

Can be used to determine whether any field values were targeting + * disallowed fields. + * @see DataBinder#setAllowedFields + */ + String[] getSuppressedFields(); + +} Index: 3rdParty_sources/spring/org/springframework/validation/BindingResultUtils.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/validation/BindingResultUtils.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/validation/BindingResultUtils.java 17 Aug 2012 15:16:04 -0000 1.1 @@ -0,0 +1,65 @@ +/* + * 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.validation; + +import java.util.Map; + +import org.springframework.util.Assert; + +/** + * Convenience methods for looking up BindingResults in a model Map. + * + * @author Juergen Hoeller + * @since 2.0 + * @see BindingResult#MODEL_KEY_PREFIX + */ +public abstract class BindingResultUtils { + + /** + * Find the BindingResult for the given name in the given model. + * @param model the model to search + * @param name the name of the target object to find a BindingResult for + * @return the BindingResult, or null if none found + * @throws IllegalStateException if the attribute found is not of type BindingResult + */ + public static BindingResult getBindingResult(Map model, String name) { + Assert.notNull(model, "Model map must not be null"); + Assert.notNull(name, "Name must not be null"); + Object attr = model.get(BindingResult.MODEL_KEY_PREFIX + name); + if (attr != null && !(attr instanceof BindingResult)) { + throw new IllegalStateException("BindingResult attribute is not of type BindingResult: " + attr); + } + return (BindingResult) attr; + } + + /** + * Find a required BindingResult for the given name in the given model. + * @param model the model to search + * @param name the name of the target object to find a BindingResult for + * @return the BindingResult (never null) + * @throws IllegalStateException if no BindingResult found + */ + public static BindingResult getRequiredBindingResult(Map model, String name) { + BindingResult bindingResult = getBindingResult(model, name); + if (bindingResult == null) { + throw new IllegalStateException("No BindingResult attribute found for name '" + name + + "'- have you exposed the correct model?"); + } + return bindingResult; + } + +} Index: 3rdParty_sources/spring/org/springframework/validation/DataBinder.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/validation/DataBinder.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/validation/DataBinder.java 17 Aug 2012 15:16:04 -0000 1.1 @@ -0,0 +1,613 @@ +/* + * 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.validation; + +import java.beans.PropertyEditor; +import java.util.HashMap; +import java.util.Map; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import org.springframework.beans.ConfigurablePropertyAccessor; +import org.springframework.beans.MutablePropertyValues; +import org.springframework.beans.PropertyAccessException; +import org.springframework.beans.PropertyAccessorUtils; +import org.springframework.beans.PropertyBatchUpdateException; +import org.springframework.beans.PropertyEditorRegistry; +import org.springframework.beans.PropertyValue; +import org.springframework.beans.PropertyValues; +import org.springframework.beans.SimpleTypeConverter; +import org.springframework.beans.TypeConverter; +import org.springframework.beans.TypeMismatchException; +import org.springframework.core.MethodParameter; +import org.springframework.util.Assert; +import org.springframework.util.ObjectUtils; +import org.springframework.util.PatternMatchUtils; +import org.springframework.util.StringUtils; + +/** + * Binder that allows for setting property values onto a target object, + * including support for validation and binding result analysis. + * The binding process can be customized through specifying allowed fields, + * required fields, custom editors, etc. + * + *

Note that there are potential security implications in failing to set an array + * of allowed fields. In the case of HTTP form POST data for example, malicious clients + * can attempt to subvert an application by supplying values for fields or properties + * that do not exist on the form. In some cases this could lead to illegal data being + * set on command objects or their nested objects. For this reason, it is + * highly recommended to specify the {@link #setAllowedFields allowedFields} property + * on the DataBinder. + * + *

The binding results can be examined via the {@link BindingResult} interface, + * extending the {@link Errors} interface: see the {@link #getBindingResult()} method. + * Missing fields and property access exceptions will be converted to {@link FieldError FieldErrors}, + * collected in the Errors instance, using the following error codes: + * + *

    + *
  • Missing field error: "required" + *
  • Type mismatch error: "typeMismatch" + *
  • Method invocation error: "methodInvocation" + *
+ * + *

By default, binding errors get resolved through the {@link BindingErrorProcessor} + * strategy, processing for missing fields and property access exceptions: see the + * {@link #setBindingErrorProcessor} method. You can override the default strategy + * if needed, for example to generate different error codes. + * + *

Custom validation errors can be added afterwards. You will typically want to resolve + * such error codes into proper user-visible error messages; this can be achieved through + * resolving each error via a {@link org.springframework.context.MessageSource}, which is + * able to resolve an {@link ObjectError}/{@link FieldError} through its + * {@link org.springframework.context.MessageSource#getMessage(org.springframework.context.MessageSourceResolvable, java.util.Locale)} + * method. The list of message codes can be customized through the {@link MessageCodesResolver} + * strategy: see the {@link #setMessageCodesResolver} method. {@link DefaultMessageCodesResolver}'s + * javadoc states details on the default resolution rules. + * + *

This generic data binder can be used in any kind of environment. + * It is typically used by Spring web MVC controllers, via the web-specific + * subclasses {@link org.springframework.web.bind.ServletRequestDataBinder} + * and {@link org.springframework.web.portlet.bind.PortletRequestDataBinder}. + * + * @author Rod Johnson + * @author Juergen Hoeller + * @author Rob Harrop + * @see #setAllowedFields + * @see #setRequiredFields + * @see #registerCustomEditor + * @see #setMessageCodesResolver + * @see #setBindingErrorProcessor + * @see #bind + * @see #getBindingResult + * @see DefaultMessageCodesResolver + * @see DefaultBindingErrorProcessor + * @see org.springframework.context.MessageSource + * @see org.springframework.web.bind.ServletRequestDataBinder + */ +public class DataBinder implements PropertyEditorRegistry, TypeConverter { + + /** Default object name used for binding: "target" */ + public static final String DEFAULT_OBJECT_NAME = "target"; + + + /** + * We'll create a lot of DataBinder instances: Let's use a static logger. + */ + protected static final Log logger = LogFactory.getLog(DataBinder.class); + + private final Object target; + + private final String objectName; + + private AbstractPropertyBindingResult bindingResult; + + private SimpleTypeConverter typeConverter; + + private BindException bindException; + + private boolean ignoreUnknownFields = true; + + private boolean ignoreInvalidFields = false; + + private String[] allowedFields; + + private String[] disallowedFields; + + private String[] requiredFields; + + private BindingErrorProcessor bindingErrorProcessor = new DefaultBindingErrorProcessor(); + + + /** + * Create a new DataBinder instance, with default object name. + * @param target the target object to bind onto (or null + * if the binder is just used to convert a plain parameter value) + * @see #DEFAULT_OBJECT_NAME + */ + public DataBinder(Object target) { + this(target, DEFAULT_OBJECT_NAME); + } + + /** + * Create a new DataBinder instance. + * @param target the target object to bind onto (or null + * if the binder is just used to convert a plain parameter value) + * @param objectName the name of the target object + */ + public DataBinder(Object target, String objectName) { + this.target = target; + this.objectName = objectName; + } + + + /** + * Return the wrapped target object. + */ + public Object getTarget() { + return this.target; + } + + /** + * Return the name of the bound object. + */ + public String getObjectName() { + return this.objectName; + } + + /** + * Initialize standard JavaBean property access for this DataBinder. + *

This is the default; an explicit call just leads to eager initialization. + * @see #initDirectFieldAccess() + */ + public void initBeanPropertyAccess() { + Assert.isNull(this.bindingResult, + "DataBinder is already initialized - call initBeanPropertyAccess before any other configuration methods"); + this.bindingResult = new BeanPropertyBindingResult(getTarget(), getObjectName()); + } + + /** + * Initialize direct field access for this DataBinder, + * as alternative to the default bean property access. + * @see #initBeanPropertyAccess() + */ + public void initDirectFieldAccess() { + Assert.isNull(this.bindingResult, + "DataBinder is already initialized - call initDirectFieldAccess before any other configuration methods"); + this.bindingResult = new DirectFieldBindingResult(getTarget(), getObjectName()); + } + + /** + * Return the internal BindingResult held by this DataBinder, + * as AbstractPropertyBindingResult. + */ + protected AbstractPropertyBindingResult getInternalBindingResult() { + if (this.bindingResult == null) { + initBeanPropertyAccess(); + } + return this.bindingResult; + } + + /** + * Return the underlying PropertyAccessor of this binder's BindingResult. + */ + protected ConfigurablePropertyAccessor getPropertyAccessor() { + return getInternalBindingResult().getPropertyAccessor(); + } + + /** + * Return this binder's underlying SimpleTypeConverter. + */ + protected SimpleTypeConverter getSimpleTypeConverter() { + if (this.typeConverter == null) { + this.typeConverter = new SimpleTypeConverter(); + } + return this.typeConverter; + } + + /** + * Return the underlying TypeConverter of this binder's BindingResult. + */ + protected PropertyEditorRegistry getPropertyEditorRegistry() { + if (getTarget() != null) { + return getInternalBindingResult().getPropertyAccessor(); + } + else { + return getSimpleTypeConverter(); + } + } + + /** + * Return the underlying TypeConverter of this binder's BindingResult. + */ + protected TypeConverter getTypeConverter() { + if (getTarget() != null) { + return getInternalBindingResult().getPropertyAccessor(); + } + else { + return getSimpleTypeConverter(); + } + } + + /** + * Return the BindingResult instance created by this DataBinder. + * This allows for convenient access to the binding results after + * a bind operation. + * @return the BindingResult instance, to be treated as BindingResult + * or as Errors instance (Errors is a super-interface of BindingResult) + * @see Errors + * @see #bind + */ + public BindingResult getBindingResult() { + return getInternalBindingResult(); + } + + /** + * Return the Errors instance for this data binder. + * @return the Errors instance, to be treated as Errors or as BindException + * @deprecated in favor of {@link #getBindingResult()}. + * Use the {@link BindException#BindException(BindingResult)} constructor + * to create a BindException instance if still needed. + * @see #getBindingResult() + */ + public BindException getErrors() { + if (this.bindException == null) { + this.bindException = new BindException(getBindingResult()); + } + return this.bindException; + } + + + /** + * Set whether to ignore unknown fields, that is, whether to ignore bind + * parameters that do not have corresponding fields in the target object. + *

Default is "true". Turn this off to enforce that all bind parameters + * must have a matching field in the target object. + *

Note that this setting only applies to binding operations + * on this DataBinder, not to retrieving values via its + * {@link #getBindingResult() BindingResult}. + * @see #bind + */ + public void setIgnoreUnknownFields(boolean ignoreUnknownFields) { + this.ignoreUnknownFields = ignoreUnknownFields; + } + + /** + * Return whether to ignore unknown fields when binding. + */ + public boolean isIgnoreUnknownFields() { + return this.ignoreUnknownFields; + } + + /** + * Set whether to ignore invalid fields, that is, whether to ignore bind + * parameters that have corresponding fields in the target object which are + * not accessible (for example because of null values in the nested path). + *

Default is "false". Turn this on to ignore bind parameters for + * nested objects in non-existing parts of the target object graph. + *

Note that this setting only applies to binding operations + * on this DataBinder, not to retrieving values via its + * {@link #getBindingResult() BindingResult}. + * @see #bind + */ + public void setIgnoreInvalidFields(boolean ignoreInvalidFields) { + this.ignoreInvalidFields = ignoreInvalidFields; + } + + /** + * Return whether to ignore invalid fields when binding. + */ + public boolean isIgnoreInvalidFields() { + return this.ignoreInvalidFields; + } + + /** + * Register fields that should be allowed for binding. Default is all + * fields. Restrict this for example to avoid unwanted modifications + * by malicious users when binding HTTP request parameters. + *

Supports "xxx*", "*xxx" and "*xxx*" patterns. More sophisticated matching + * can be implemented by overriding the isAllowed method. + *

Alternatively, specify a list of disallowed fields. + * @param allowedFields array of field names + * @see #setDisallowedFields + * @see #isAllowed(String) + * @see org.springframework.web.bind.ServletRequestDataBinder + */ + public void setAllowedFields(String[] allowedFields) { + this.allowedFields = PropertyAccessorUtils.canonicalPropertyNames(allowedFields); + } + + /** + * Return the fields that should be allowed for binding. + * @return array of field names + */ + public String[] getAllowedFields() { + return this.allowedFields; + } + + /** + * Register fields that should not be allowed for binding. Default is none. + * Mark fields as disallowed for example to avoid unwanted modifications + * by malicious users when binding HTTP request parameters. + *

Supports "xxx*", "*xxx" and "*xxx*" patterns. More sophisticated matching + * can be implemented by overriding the isAllowed method. + *

Alternatively, specify a list of allowed fields. + * @param disallowedFields array of field names + * @see #setAllowedFields + * @see #isAllowed(String) + * @see org.springframework.web.bind.ServletRequestDataBinder + */ + public void setDisallowedFields(String[] disallowedFields) { + this.disallowedFields = PropertyAccessorUtils.canonicalPropertyNames(disallowedFields); + } + + /** + * Return the fields that should not be allowed for binding. + * @return array of field names + */ + public String[] getDisallowedFields() { + return this.disallowedFields; + } + + /** + * Register fields that are required for each binding process. + *

If one of the specified fields is not contained in the list of + * incoming property values, a corresponding "missing field" error + * will be created, with error code "required" (by the default + * binding error processor). + * @param requiredFields array of field names + * @see #setBindingErrorProcessor + * @see DefaultBindingErrorProcessor#MISSING_FIELD_ERROR_CODE + */ + public void setRequiredFields(String[] requiredFields) { + this.requiredFields = PropertyAccessorUtils.canonicalPropertyNames(requiredFields); + if (logger.isDebugEnabled()) { + logger.debug("DataBinder requires binding of required fields [" + + StringUtils.arrayToCommaDelimitedString(requiredFields) + "]"); + } + } + + /** + * Return the fields that are required for each binding process. + * @return array of field names + */ + public String[] getRequiredFields() { + return this.requiredFields; + } + + /** + * Set whether to extract the old field value when applying a + * property editor to a new value for a field. + *

Default is "true", exposing previous field values to custom editors. + * Turn this to "false" to avoid side effects caused by getters. + */ + public void setExtractOldValueForEditor(boolean extractOldValueForEditor) { + getPropertyAccessor().setExtractOldValueForEditor(extractOldValueForEditor); + } + + /** + * Set the strategy to use for resolving errors into message codes. + * Applies the given strategy to the underlying errors holder. + *

Default is a DefaultMessageCodesResolver. + * @see BeanPropertyBindingResult#setMessageCodesResolver + * @see DefaultMessageCodesResolver + */ + public void setMessageCodesResolver(MessageCodesResolver messageCodesResolver) { + getInternalBindingResult().setMessageCodesResolver(messageCodesResolver); + } + + /** + * Set the strategy to use for processing binding errors, that is, + * required field errors and PropertyAccessExceptions. + *

Default is a DefaultBindingErrorProcessor. + * @see DefaultBindingErrorProcessor + */ + public void setBindingErrorProcessor(BindingErrorProcessor bindingErrorProcessor) { + this.bindingErrorProcessor = bindingErrorProcessor; + } + + /** + * Return the strategy for processing binding errors. + */ + public BindingErrorProcessor getBindingErrorProcessor() { + return this.bindingErrorProcessor; + } + + + //--------------------------------------------------------------------- + // Implementation of PropertyEditorRegistry/TypeConverter interface + //--------------------------------------------------------------------- + + public void registerCustomEditor(Class requiredType, PropertyEditor propertyEditor) { + getPropertyEditorRegistry().registerCustomEditor(requiredType, propertyEditor); + } + + public void registerCustomEditor(Class requiredType, String field, PropertyEditor propertyEditor) { + getPropertyEditorRegistry().registerCustomEditor(requiredType, field, propertyEditor); + } + + public PropertyEditor findCustomEditor(Class requiredType, String propertyPath) { + return getPropertyEditorRegistry().findCustomEditor(requiredType, propertyPath); + } + + public Object convertIfNecessary(Object value, Class requiredType) throws TypeMismatchException { + return getTypeConverter().convertIfNecessary(value, requiredType); + } + + public Object convertIfNecessary( + Object value, Class requiredType, MethodParameter methodParam) throws TypeMismatchException { + + return getTypeConverter().convertIfNecessary(value, requiredType, methodParam); + } + + + /** + * Bind the given property values to this binder's target. + *

This call can create field errors, representing basic binding + * errors like a required field (code "required"), or type mismatch + * between value and bean property (code "typeMismatch"). + *

Note that the given PropertyValues should be a throwaway instance: + * For efficiency, it will be modified to just contain allowed fields if it + * implements the MutablePropertyValues interface; else, an internal mutable + * copy will be created for this purpose. Pass in a copy of the PropertyValues + * if you want your original instance to stay unmodified in any case. + * @param pvs property values to bind + * @see #doBind(org.springframework.beans.MutablePropertyValues) + */ + public void bind(PropertyValues pvs) { + MutablePropertyValues mpvs = (pvs instanceof MutablePropertyValues) ? + (MutablePropertyValues) pvs : new MutablePropertyValues(pvs); + doBind(mpvs); + } + + /** + * Actual implementation of the binding process, working with the + * passed-in MutablePropertyValues instance. + * @param mpvs the property values to bind, + * as MutablePropertyValues instance + * @see #checkAllowedFields + * @see #checkRequiredFields + * @see #applyPropertyValues + */ + protected void doBind(MutablePropertyValues mpvs) { + checkAllowedFields(mpvs); + checkRequiredFields(mpvs); + applyPropertyValues(mpvs); + } + + /** + * Check the given property values against the allowed fields, + * removing values for fields that are not allowed. + * @param mpvs the property values to be bound (can be modified) + * @see #getAllowedFields + * @see #isAllowed(String) + */ + protected void checkAllowedFields(MutablePropertyValues mpvs) { + PropertyValue[] pvs = mpvs.getPropertyValues(); + for (int i = 0; i < pvs.length; i++) { + PropertyValue pv = pvs[i]; + String field = PropertyAccessorUtils.canonicalPropertyName(pv.getName()); + if (!isAllowed(field)) { + mpvs.removePropertyValue(pv); + getBindingResult().recordSuppressedField(field); + if (logger.isDebugEnabled()) { + logger.debug("Field [" + field + "] has been removed from PropertyValues " + + "and will not be bound, because it has not been found in the list of allowed fields"); + } + } + } + } + + /** + * Return if the given field is allowed for binding. + * Invoked for each passed-in property value. + *

The default implementation checks for "xxx*", "*xxx" and "*xxx*" matches, + * as well as direct equality, in the specified lists of allowed fields and + * disallowed fields. A field matching a disallowed pattern will not be accepted + * even if it also happens to match a pattern in the allowed list. + *

Can be overridden in subclasses. + * @param field the field to check + * @return if the field is allowed + * @see #setAllowedFields + * @see #setDisallowedFields + * @see org.springframework.util.PatternMatchUtils#simpleMatch(String, String) + */ + protected boolean isAllowed(String field) { + String[] allowed = getAllowedFields(); + String[] disallowed = getDisallowedFields(); + return ((ObjectUtils.isEmpty(allowed) || PatternMatchUtils.simpleMatch(allowed, field)) && + (ObjectUtils.isEmpty(disallowed) || !PatternMatchUtils.simpleMatch(disallowed, field))); + } + + /** + * Check the given property values against the required fields, + * generating missing field errors where appropriate. + * @param mpvs the property values to be bound (can be modified) + * @see #getRequiredFields + * @see #getBindingErrorProcessor + * @see BindingErrorProcessor#processMissingFieldError + */ + protected void checkRequiredFields(MutablePropertyValues mpvs) { + String[] requiredFields = getRequiredFields(); + if (!ObjectUtils.isEmpty(requiredFields)) { + Map propertyValues = new HashMap(); + PropertyValue[] pvs = mpvs.getPropertyValues(); + for (int i = 0; i < pvs.length; i++) { + PropertyValue pv = pvs[i]; + String canonicalName = PropertyAccessorUtils.canonicalPropertyName(pv.getName()); + propertyValues.put(canonicalName, pv); + } + for (int i = 0; i < requiredFields.length; i++) { + String field = requiredFields[i]; + PropertyValue pv = (PropertyValue) propertyValues.get(field); + if (pv == null || pv.getValue() == null || + (pv.getValue() instanceof String && !StringUtils.hasText((String) pv.getValue()))) { + // Use bind error processor to create FieldError. + getBindingErrorProcessor().processMissingFieldError(field, getInternalBindingResult()); + // Remove property from property values to bind: + // It has already caused a field error with a rejected value. + if (pv != null) { + mpvs.removePropertyValue(pv); + propertyValues.remove(field); + } + } + } + } + } + + /** + * Apply given property values to the target object. + *

Default implementation applies all of the supplied property + * values as bean property values. By default, unknown fields will + * be ignored. + * @param mpvs the property values to be bound (can be modified) + * @see #getTarget + * @see #getPropertyAccessor + * @see #isIgnoreUnknownFields + * @see #getBindingErrorProcessor + * @see BindingErrorProcessor#processPropertyAccessException + */ + protected void applyPropertyValues(MutablePropertyValues mpvs) { + try { + // Bind request parameters onto target object. + getPropertyAccessor().setPropertyValues(mpvs, isIgnoreUnknownFields(), isIgnoreInvalidFields()); + } + catch (PropertyBatchUpdateException ex) { + // Use bind error processor to create FieldErrors. + PropertyAccessException[] exs = ex.getPropertyAccessExceptions(); + for (int i = 0; i < exs.length; i++) { + getBindingErrorProcessor().processPropertyAccessException(exs[i], getInternalBindingResult()); + } + } + } + + + /** + * Close this DataBinder, which may result in throwing + * a BindException if it encountered any errors. + * @return the model Map, containing target object and Errors instance + * @throws BindException if there were any errors in the bind operation + * @see BindingResult#getModel() + */ + public Map close() throws BindException { + if (getBindingResult().hasErrors()) { + throw new BindException(getBindingResult()); + } + return getBindingResult().getModel(); + } + +} Index: 3rdParty_sources/spring/org/springframework/validation/DefaultBindingErrorProcessor.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/validation/DefaultBindingErrorProcessor.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/validation/DefaultBindingErrorProcessor.java 17 Aug 2012 15:16:04 -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.validation; + +import org.springframework.beans.PropertyAccessException; +import org.springframework.context.support.DefaultMessageSourceResolvable; + +/** + * Default {@link BindingErrorProcessor} implementation. + * + *

Uses the "required" error code and the field name to resolve message codes + * for a missing field error. + * + *

Creates a FieldError for each PropertyAccessException + * given, using the PropertyAccessException's error code ("typeMismatch", + * "methodInvocation") for resolving message codes. + * + * @author Alef Arendsen + * @author Juergen Hoeller + * @since 1.2 + * @see #MISSING_FIELD_ERROR_CODE + * @see DataBinder#setBindingErrorProcessor + * @see BeanPropertyBindingResult#addError + * @see BeanPropertyBindingResult#resolveMessageCodes + * @see org.springframework.beans.PropertyAccessException#getErrorCode + * @see org.springframework.beans.TypeMismatchException#ERROR_CODE + * @see org.springframework.beans.MethodInvocationException#ERROR_CODE + */ +public class DefaultBindingErrorProcessor implements BindingErrorProcessor { + + /** + * Error code that a missing field error (i.e. a required field not + * found in the list of property values) will be registered with: + * "required". + */ + public static final String MISSING_FIELD_ERROR_CODE = "required"; + + + public void processMissingFieldError(String missingField, BindingResult bindingResult) { + // Create field error with code "required". + String fixedField = bindingResult.getNestedPath() + missingField; + String[] codes = bindingResult.resolveMessageCodes(MISSING_FIELD_ERROR_CODE, missingField); + Object[] arguments = getArgumentsForBindError(bindingResult.getObjectName(), fixedField); + bindingResult.addError(new FieldError( + bindingResult.getObjectName(), fixedField, "", true, + codes, arguments, "Field '" + fixedField + "' is required")); + } + + public void processPropertyAccessException(PropertyAccessException ex, BindingResult bindingResult) { + // Create field error with the exceptions's code, e.g. "typeMismatch". + String field = ex.getPropertyChangeEvent().getPropertyName(); + Object value = ex.getPropertyChangeEvent().getNewValue(); + String[] codes = bindingResult.resolveMessageCodes(ex.getErrorCode(), field); + Object[] arguments = getArgumentsForBindError(bindingResult.getObjectName(), field); + bindingResult.addError(new FieldError( + bindingResult.getObjectName(), field, value, true, + codes, arguments, ex.getLocalizedMessage())); + } + + /** + * Return FieldError arguments for a binding error on the given field. + * Invoked for each missing required fields and each type mismatch. + *

Default implementation returns a DefaultMessageSourceResolvable + * with "objectName.field" and "field" as codes. + * @param field the field that caused the binding error + * @return the Object array that represents the FieldError arguments + * @see org.springframework.validation.FieldError#getArguments + * @see org.springframework.context.support.DefaultMessageSourceResolvable + */ + protected Object[] getArgumentsForBindError(String objectName, String field) { + String[] codes = new String[] {objectName + Errors.NESTED_PATH_SEPARATOR + field, field}; + String defaultMessage = field; + return new Object[] {new DefaultMessageSourceResolvable(codes, defaultMessage)}; + } + +} Index: 3rdParty_sources/spring/org/springframework/validation/DefaultMessageCodesResolver.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/validation/DefaultMessageCodesResolver.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/validation/DefaultMessageCodesResolver.java 17 Aug 2012 15:16:04 -0000 1.1 @@ -0,0 +1,178 @@ +/* + * 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.validation; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import org.springframework.util.StringUtils; + +/** + * Default implementation of the {@link MessageCodesResolver} interface. + * + *

Will create two message codes for an object error, in the following order: + *

    + *
  • 1.: code + "." + object name + *
  • 2.: code + *
+ * + *

Will create four message codes for a field specification, in the following order: + *

    + *
  • 1.: code + "." + object name + "." + field + *
  • 2.: code + "." + field + *
  • 3.: code + "." + field type + *
  • 4.: code + *
+ * + *

For example, in case of code "typeMismatch", object name "user", field "age": + *

    + *
  • 1. try "typeMismatch.user.age" + *
  • 2. try "typeMismatch.age" + *
  • 3. try "typeMismatch.int" + *
  • 4. try "typeMismatch" + *
+ * + *

This resolution algorithm thus can be leveraged for example to show + * specific messages for binding errors like "required" and "typeMismatch": + *

    + *
  • at the object + field level ("age" field, but only on "user"); + *
  • at the field level (all "age" fields, no matter which object name); + *
  • or at the general level (all fields, on any object). + *
+ * + *

In case of array, {@link List} or {@link java.util.Map} properties, + * both codes for specific elements and for the whole collection are + * generated. Assuming a field "name" of an array "groups" in object "user": + *

    + *
  • 1. try "typeMismatch.user.groups[0].name" + *
  • 2. try "typeMismatch.user.groups.name" + *
  • 3. try "typeMismatch.groups[0].name" + *
  • 4. try "typeMismatch.groups.name" + *
  • 5. try "typeMismatch.name" + *
  • 6. try "typeMismatch.java.lang.String" + *
  • 7. try "typeMismatch" + *
+ * + *

In order to group all codes into a specific category within your resource bundles, + * e.g. "validation.typeMismatch.name" instead of the default "typeMismatch.name", + * consider specifying a {@link #setPrefix prefix} to be applied. + * + * @author Juergen Hoeller + * @since 1.0.1 + */ +public class DefaultMessageCodesResolver implements MessageCodesResolver, Serializable { + + /** + * The separator that this implementation uses when resolving message codes. + */ + public static final String CODE_SEPARATOR = "."; + + + private String prefix = ""; + + + /** + * Specify a prefix to be applied to any code built by this resolver. + *

Default is none. Specify, for example, "validation." to get + * error codes like "validation.typeMismatch.name". + */ + public void setPrefix(String prefix) { + this.prefix = (prefix != null ? prefix : ""); + } + + /** + * Return the prefix to be applied to any code built by this resolver. + *

Returns an empty String in case of no prefix. + */ + protected String getPrefix() { + return this.prefix; + } + + + public String[] resolveMessageCodes(String errorCode, String objectName) { + return new String[] { + postProcessMessageCode(errorCode + CODE_SEPARATOR + objectName), + postProcessMessageCode(errorCode)}; + } + + /** + * Build the code list for the given code and field: an + * object/field-specific code, a field-specific code, a plain error code. + *

Arrays, Lists and Maps are resolved both for specific elements and + * the whole collection. + *

See the {@link DefaultMessageCodesResolver class level Javadoc} for + * details on the generated codes. + * @return the list of codes + */ + public String[] resolveMessageCodes(String errorCode, String objectName, String field, Class fieldType) { + List codeList = new ArrayList(); + List fieldList = new ArrayList(); + buildFieldList(field, fieldList); + for (Iterator it = fieldList.iterator(); it.hasNext();) { + String fieldInList = (String) it.next(); + codeList.add(postProcessMessageCode(errorCode + CODE_SEPARATOR + objectName + CODE_SEPARATOR + fieldInList)); + } + int dotIndex = field.lastIndexOf('.'); + if (dotIndex != -1) { + buildFieldList(field.substring(dotIndex + 1), fieldList); + } + for (Iterator it = fieldList.iterator(); it.hasNext();) { + String fieldInList = (String) it.next(); + codeList.add(postProcessMessageCode(errorCode + CODE_SEPARATOR + fieldInList)); + } + if (fieldType != null) { + codeList.add(postProcessMessageCode(errorCode + CODE_SEPARATOR + fieldType.getName())); + } + codeList.add(postProcessMessageCode(errorCode)); + return StringUtils.toStringArray(codeList); + } + + /** + * Add both keyed and non-keyed entries for the supplied field + * to the supplied field list. + */ + protected void buildFieldList(String field, List fieldList) { + fieldList.add(field); + String plainField = field; + int keyIndex = plainField.lastIndexOf('['); + while (keyIndex != -1) { + int endKeyIndex = plainField.indexOf(']', keyIndex); + if (endKeyIndex != -1) { + plainField = plainField.substring(0, keyIndex) + plainField.substring(endKeyIndex + 1); + fieldList.add(plainField); + keyIndex = plainField.lastIndexOf('['); + } + else { + keyIndex = -1; + } + } + } + + /** + * Post-process the given message code, built by this resolver. + *

The default implementation applies the specified prefix, if any. + * @param code the message code as built by this resolver + * @return the final message code to be returned + * @see #setPrefix + */ + protected String postProcessMessageCode(String code) { + return getPrefix() + code; + } + +} Index: 3rdParty_sources/spring/org/springframework/validation/DirectFieldBindingResult.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/validation/DirectFieldBindingResult.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/validation/DirectFieldBindingResult.java 17 Aug 2012 15:16:04 -0000 1.1 @@ -0,0 +1,81 @@ +/* + * 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.validation; + +import org.springframework.beans.ConfigurablePropertyAccessor; +import org.springframework.beans.PropertyAccessorFactory; +import org.springframework.util.Assert; + +/** + * Special implementation of the Errors and BindingResult interfaces, + * supporting registration and evaluation of binding errors on value objects. + * Performs direct field access instead of going through JavaBean getters. + * + *

This implementation just supports fields in the actual target object. + * It is not able to traverse nested fields. + * + * @author Juergen Hoeller + * @since 2.0 + * @see DataBinder#getBindingResult() + * @see DataBinder#initDirectFieldAccess() + * @see BeanPropertyBindingResult + */ +public class DirectFieldBindingResult extends AbstractPropertyBindingResult { + + private final Object target; + + private transient ConfigurablePropertyAccessor directFieldAccessor; + + + /** + * Create a new DirectFieldBindingResult instance. + * @param target the target object to bind onto + * @param objectName the name of the target object + */ + public DirectFieldBindingResult(Object target, String objectName) { + super(objectName); + this.target = target; + } + + + public final Object getTarget() { + return this.target; + } + + /** + * Returns the DirectFieldAccessor that this instance uses. + * Creates a new one if none existed before. + * @see #createDirectFieldAccessor() + */ + public final ConfigurablePropertyAccessor getPropertyAccessor() { + if (this.directFieldAccessor == null) { + this.directFieldAccessor = createDirectFieldAccessor(); + this.directFieldAccessor.setExtractOldValueForEditor(true); + } + return this.directFieldAccessor; + } + + /** + * Create a new DirectFieldAccessor for the underlying target object. + * @see #getTarget() + */ + protected ConfigurablePropertyAccessor createDirectFieldAccessor() { + Assert.state(this.target != null, "Cannot access fields on null target instance '" + getObjectName() + "'!"); + return PropertyAccessorFactory.forDirectFieldAccess(this.target); + } + +} Index: 3rdParty_sources/spring/org/springframework/validation/Errors.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/validation/Errors.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/validation/Errors.java 17 Aug 2012 15:16:04 -0000 1.1 @@ -0,0 +1,301 @@ +/* + * 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.validation; + +import java.util.List; + +import org.springframework.beans.PropertyAccessor; + +/** + * Stores and exposes information about data-binding and validation + * errors for a specific object. + * + *

Field names can be properties of the target object (e.g. "name" + * when binding to a customer object), or nested fields in case of + * subobjects (e.g. "address.street"). Supports subtree navigation + * via {@link #setNestedPath(String)}: for example, an + * AddressValidator validates "address", not being aware + * that this is a subobject of customer. + * + *

Note: Errors objects are single-threaded. + * + * @author Rod Johnson + * @author Juergen Hoeller + * @see #setNestedPath + * @see BindException + * @see DataBinder + * @see ValidationUtils + */ +public interface Errors { + + /** + * The separator between path elements in a nested path, + * for example in "customer.name" or "customer.address.street". + *

"." = same as the + * {@link org.springframework.beans.PropertyAccessor#NESTED_PROPERTY_SEPARATOR nested property separator} + * in the beans package. + */ + String NESTED_PATH_SEPARATOR = PropertyAccessor.NESTED_PROPERTY_SEPARATOR; + + + /** + * Return the name of the bound root object. + */ + String getObjectName(); + + /** + * Allow context to be changed so that standard validators can validate + * subtrees. Reject calls prepend the given path to the field names. + *

For example, an address validator could validate the subobject + * "address" of a customer object. + * @param nestedPath nested path within this object, + * e.g. "address" (defaults to "", null is also acceptable). + * Can end with a dot: both "address" and "address." are valid. + */ + void setNestedPath(String nestedPath); + + /** + * Return the current nested path of this {@link Errors} object. + *

Returns a nested path with a dot, i.e. "address.", for easy + * building of concatenated paths. Default is an empty String. + */ + String getNestedPath(); + + /** + * Push the given sub path onto the nested path stack. + *

A {@link #popNestedPath()} call will reset the original + * nested path before the corresponding + * pushNestedPath(String) call. + *

Using the nested path stack allows to set temporary nested paths + * for subobjects without having to worry about a temporary path holder. + *

For example: current path "spouse.", pushNestedPath("child") -> + * result path "spouse.child."; popNestedPath() -> "spouse." again. + * @param subPath the sub path to push onto the nested path stack + * @see #popNestedPath + */ + void pushNestedPath(String subPath); + + /** + * Pop the former nested path from the nested path stack. + * @throws IllegalStateException if there is no former nested path on the stack + * @see #pushNestedPath + */ + void popNestedPath() throws IllegalStateException; + + /** + * Register a global error for the entire target object, + * using the given error description. + * @param errorCode error code, interpretable as a message key + */ + void reject(String errorCode); + + /** + * Register a global error for the entire target object, + * using the given error description. + * @param errorCode error code, interpretable as a message key + * @param defaultMessage fallback default message + */ + void reject(String errorCode, String defaultMessage); + + /** + * Register a global error for the entire target object, + * using the given error description. + * @param errorCode error code, interpretable as a message key + * @param errorArgs error arguments, for argument binding via MessageFormat + * (can be null) + * @param defaultMessage fallback default message + */ + void reject(String errorCode, Object[] errorArgs, String defaultMessage); + + /** + * Register a field error for the specified field of the current object + * (respecting the current nested path, if any), using the given error + * description. + *

The field name may be null or empty String to indicate + * the current object itself rather than a field of it. This may result + * in a corresponding field error within the nested object graph or a + * global error if the current object is the top object. + * @param field the field name (may be null or empty String) + * @param errorCode error code, interpretable as a message key + * @see #getNestedPath() + */ + void rejectValue(String field, String errorCode); + + /** + * Register a field error for the specified field of the current object + * (respecting the current nested path, if any), using the given error + * description. + *

The field name may be null or empty String to indicate + * the current object itself rather than a field of it. This may result + * in a corresponding field error within the nested object graph or a + * global error if the current object is the top object. + * @param field the field name (may be null or empty String) + * @param errorCode error code, interpretable as a message key + * @param defaultMessage fallback default message + * @see #getNestedPath() + */ + void rejectValue(String field, String errorCode, String defaultMessage); + + /** + * Register a field error for the specified field of the current object + * (respecting the current nested path, if any), using the given error + * description. + *

The field name may be null or empty String to indicate + * the current object itself rather than a field of it. This may result + * in a corresponding field error within the nested object graph or a + * global error if the current object is the top object. + * @param field the field name (may be null or empty String) + * @param errorCode error code, interpretable as a message key + * @param errorArgs error arguments, for argument binding via MessageFormat + * (can be null) + * @param defaultMessage fallback default message + * @see #getNestedPath() + */ + void rejectValue(String field, String errorCode, Object[] errorArgs, String defaultMessage); + + /** + * Add all errors from the given Errors instance to this + * Errors instance. + *

This is a onvenience method to avoid repeated reject(..) + * calls for merging an Errors instance into another + * Errors instance. + *

Note that the passed-in Errors instance is supposed + * to refer to the same target object, or at least contain compatible errors + * that apply to the target object of this Errors instance. + * @param errors the Errors instance to merge in + */ + void addAllErrors(Errors errors); + + /** + * Return if there were any errors. + */ + boolean hasErrors(); + + /** + * Return the total number of errors. + */ + int getErrorCount(); + + /** + * Get all errors, both global and field ones. + * @return List of {@link ObjectError} instances + */ + List getAllErrors(); + + /** + * Are there any global errors? + * @return true if there are any global errors + * @see #hasFieldErrors() + */ + boolean hasGlobalErrors(); + + /** + * Return the number of global errors. + * @return the number of global errors + * @see #getFieldErrorCount() + */ + int getGlobalErrorCount(); + + /** + * Get all global errors. + * @return List of ObjectError instances + */ + List getGlobalErrors(); + + /** + * Get the first global error, if any. + * @return the global error, or null + */ + ObjectError getGlobalError(); + + /** + * Are there any field errors? + * @return true if there are any errors associated with a field + * @see #hasGlobalErrors() + */ + boolean hasFieldErrors(); + + /** + * Return the number of errors associated with a field. + * @return the number of errors associated with a field + * @see #getGlobalErrorCount() + */ + int getFieldErrorCount(); + + /** + * Get all errors associated with a field. + * @return a List of {@link FieldError} instances + */ + List getFieldErrors(); + + /** + * Get the first error associated with a field, if any. + * @return the field-specific error, or null + */ + FieldError getFieldError(); + + /** + * Are there any errors associated with the given field? + * @param field the field name + * @return true if there were any errors associated with the given field + */ + boolean hasFieldErrors(String field); + + /** + * Return the number of errors associated with the given field. + * @param field the field name + * @return the number of errors associated with the given field + */ + int getFieldErrorCount(String field); + + /** + * Get all errors associated with the given field. + *

Implementations should support not only full field names like + * "name" but also pattern matches like "na*" or "address.*". + * @param field the field name + * @return a List of {@link FieldError} instances + */ + List getFieldErrors(String field); + + /** + * Get the first error associated with the given field, if any. + * @param field the field name + * @return the field-specific error, or null + */ + FieldError getFieldError(String field); + + /** + * Return the current value of the given field, either the current + * bean property value or a rejected update from the last binding. + *

Allows for convenient access to user-specified field values, + * even if there were type mismatches. + * @param field the field name + * @return the current value of the given field + */ + Object getFieldValue(String field); + + /** + * Return the type of a given field. + *

Implementations should be able to determine the type even + * when the field value is null, for example from some + * associated descriptor. + * @param field the field name + * @return the type of the field, or null if not determinable + */ + Class getFieldType(String field); + +} Index: 3rdParty_sources/spring/org/springframework/validation/FieldError.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/validation/FieldError.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/validation/FieldError.java 17 Aug 2012 15:16:04 -0000 1.1 @@ -0,0 +1,125 @@ +/* + * 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.validation; + +import org.springframework.util.Assert; +import org.springframework.util.ObjectUtils; + +/** + * Encapsulates a field error, that is, a reason for rejecting a specific + * field value. + * + *

See the {@link DefaultMessageCodesResolver} javadoc for details on + * how a message code list is built for a FieldError. + * + * @author Rod Johnson + * @author Juergen Hoeller + * @since 10.03.2003 + * @see DefaultMessageCodesResolver + */ +public class FieldError extends ObjectError { + + private final String field; + + private final Object rejectedValue; + + private final boolean bindingFailure; + + + /** + * Create a new FieldError instance. + * @param objectName the name of the affected object + * @param field the affected field of the object + * @param defaultMessage the default message to be used to resolve this message + */ + public FieldError(String objectName, String field, String defaultMessage) { + this(objectName, field, null, false, null, null, defaultMessage); + } + + /** + * Create a new FieldError instance. + * @param objectName the name of the affected object + * @param field the affected field of the object + * @param rejectedValue the rejected field value + * @param bindingFailure whether this error represents a binding failure + * (like a type mismatch); else, it is a validation failure + * @param codes the codes to be used to resolve this message + * @param arguments the array of arguments to be used to resolve this message + * @param defaultMessage the default message to be used to resolve this message + */ + public FieldError( + String objectName, String field, Object rejectedValue, boolean bindingFailure, + String[] codes, Object[] arguments, String defaultMessage) { + + super(objectName, codes, arguments, defaultMessage); + Assert.notNull(field, "Field must not be null"); + this.field = field; + this.rejectedValue = rejectedValue; + this.bindingFailure = bindingFailure; + } + + + /** + * Return the affected field of the object. + */ + public String getField() { + return this.field; + } + + /** + * Return the rejected field value. + */ + public Object getRejectedValue() { + return this.rejectedValue; + } + + /** + * Return whether this error represents a binding failure + * (like a type mismatch); otherwise it is a validation failure. + */ + public boolean isBindingFailure() { + return this.bindingFailure; + } + + + public String toString() { + return "Field error in object '" + getObjectName() + "' on field '" + this.field + + "': rejected value [" + this.rejectedValue + "]; " + resolvableToString(); + } + + public boolean equals(Object other) { + if (this == other) { + return true; + } + if (!super.equals(other)) { + return false; + } + FieldError otherError = (FieldError) other; + return getField().equals(otherError.getField()) && + ObjectUtils.nullSafeEquals(getRejectedValue(), otherError.getRejectedValue()) && + isBindingFailure() == otherError.isBindingFailure(); + } + + public int hashCode() { + int hashCode = super.hashCode(); + hashCode = 29 * hashCode + getField().hashCode(); + hashCode = 29 * hashCode + ObjectUtils.nullSafeHashCode(getRejectedValue()); + hashCode = 29 * hashCode + (isBindingFailure() ? 1 : 0); + return hashCode; + } + +} Index: 3rdParty_sources/spring/org/springframework/validation/MapBindingResult.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/validation/MapBindingResult.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/validation/MapBindingResult.java 17 Aug 2012 15:16:04 -0000 1.1 @@ -0,0 +1,65 @@ +/* + * 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.validation; + +import java.io.Serializable; +import java.util.Map; + +import org.springframework.util.Assert; + +/** + * Map-based implementation of the BindingResult interface, + * supporting registration and evaluation of binding errors on + * Map attributes. + * + *

Can be used as errors holder for custom binding onto a + * Map, for example when invoking a Validator for a Map object. + * + * @author Juergen Hoeller + * @since 2.0 + * @see java.util.Map + */ +public class MapBindingResult extends AbstractBindingResult implements Serializable { + + private final Map target; + + + /** + * Create a new MapBindingResult instance. + * @param target the target Map to bind onto + * @param objectName the name of the target object + */ + public MapBindingResult(Map target, String objectName) { + super(objectName); + Assert.notNull(target, "Target Map must not be null"); + this.target = target; + } + + + public final Map getTargetMap() { + return this.target; + } + + public final Object getTarget() { + return this.target; + } + + protected Object getActualFieldValue(String field) { + return this.target.get(field); + } + +} Index: 3rdParty_sources/spring/org/springframework/validation/MessageCodesResolver.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/validation/MessageCodesResolver.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/validation/MessageCodesResolver.java 17 Aug 2012 15:16:04 -0000 1.1 @@ -0,0 +1,55 @@ +/* + * 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.validation; + +/** + * Strategy interface for building message codes from validation error codes. + * Used by DataBinder to build the codes list for ObjectErrors and FieldErrors. + * + *

The resulting message codes correspond to the codes of a + * MessageSourceResolvable (as implemented by ObjectError and FieldError). + * + * @author Juergen Hoeller + * @since 1.0.1 + * @see DataBinder#setMessageCodesResolver + * @see ObjectError + * @see FieldError + * @see org.springframework.context.MessageSourceResolvable#getCodes() + */ +public interface MessageCodesResolver { + + /** + * Build message codes for the given error code and object name. + * Used for building the codes list of an ObjectError. + * @param errorCode the error code used for rejecting the object + * @param objectName the name of the object + * @return the message codes to use + */ + String[] resolveMessageCodes(String errorCode, String objectName); + + /** + * Build message codes for the given error code and field specification. + * Used for building the codes list of an FieldError. + * @param errorCode the error code used for rejecting the value + * @param objectName the name of the object + * @param field the field name + * @param fieldType the field type (may be null if not determinable) + * @return the message codes to use + */ + String[] resolveMessageCodes(String errorCode, String objectName, String field, Class fieldType); + +} Index: 3rdParty_sources/spring/org/springframework/validation/ObjectError.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/validation/ObjectError.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/validation/ObjectError.java 17 Aug 2012 15:16:04 -0000 1.1 @@ -0,0 +1,89 @@ +/* + * 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.validation; + +import org.springframework.context.support.DefaultMessageSourceResolvable; +import org.springframework.util.Assert; + +/** + * Encapsulates an object error, that is, a global reason for rejecting + * an object. + * + *

See the {@link DefaultMessageCodesResolver} javadoc for details on + * how a message code list is built for an ObjectError. + * + * @author Juergen Hoeller + * @see FieldError + * @see DefaultMessageCodesResolver + * @since 10.03.2003 + */ +public class ObjectError extends DefaultMessageSourceResolvable { + + private final String objectName; + + + /** + * Create a new instance of the ObjectError class. + * @param objectName the name of the affected object + * @param defaultMessage the default message to be used to resolve this message + */ + public ObjectError(String objectName, String defaultMessage) { + this(objectName, null, null, defaultMessage); + } + + /** + * Create a new instance of the ObjectError class. + * @param objectName the name of the affected object + * @param codes the codes to be used to resolve this message + * @param arguments the array of arguments to be used to resolve this message + * @param defaultMessage the default message to be used to resolve this message + */ + public ObjectError(String objectName, String[] codes, Object[] arguments, String defaultMessage) { + super(codes, arguments, defaultMessage); + Assert.notNull(objectName, "Object name must not be null"); + this.objectName = objectName; + } + + + /** + * Return the name of the affected object. + */ + public String getObjectName() { + return this.objectName; + } + + + public String toString() { + return "Error in object '" + this.objectName + "': " + resolvableToString(); + } + + public boolean equals(Object other) { + if (this == other) { + return true; + } + if (!(getClass().equals(other.getClass())) || !super.equals(other)) { + return false; + } + ObjectError otherError = (ObjectError) other; + return getObjectName().equals(otherError.getObjectName()); + } + + public int hashCode() { + return super.hashCode() * 29 + getObjectName().hashCode(); + } + +} Index: 3rdParty_sources/spring/org/springframework/validation/ValidationUtils.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/validation/ValidationUtils.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/validation/ValidationUtils.java 17 Aug 2012 15:16:04 -0000 1.1 @@ -0,0 +1,230 @@ +/* + * 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.validation; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import org.springframework.util.Assert; +import org.springframework.util.StringUtils; + +/** + * Utility class offering convenient methods for invoking a {@link Validator} + * and for rejecting empty fields. + * + *

Checks for an empty field in Validator implementations can become + * one-liners when using {@link #rejectIfEmpty} or {@link #rejectIfEmptyOrWhitespace}. + * + * @author Juergen Hoeller + * @author Dmitriy Kopylenko + * @since 06.05.2003 + * @see Validator + * @see Errors + */ +public abstract class ValidationUtils { + + private static Log logger = LogFactory.getLog(ValidationUtils.class); + + + /** + * Invoke the given {@link Validator} for the supplied object and + * {@link Errors} instance. + * @param validator the Validator to be invoked (must not be null) + * @param obj the object to bind the parameters to + * @param errors the {@link Errors} instance that should store the errors (must not be null) + * @throws IllegalArgumentException if either of the Validator or Errors arguments is null; + * or if the supplied Validator does not {@link Validator#supports(Class) support} + * the validation of the supplied object's type + */ + public static void invokeValidator(Validator validator, Object obj, Errors errors) { + Assert.notNull(validator, "Validator must not be null"); + Assert.notNull(errors, "Errors object must not be null"); + if (logger.isDebugEnabled()) { + logger.debug("Invoking validator [" + validator + "]"); + } + if (obj != null && !validator.supports(obj.getClass())) { + throw new IllegalArgumentException( + "Validator [" + validator.getClass() + "] does not support [" + obj.getClass() + "]"); + } + validator.validate(obj, errors); + if (logger.isDebugEnabled()) { + if (errors.hasErrors()) { + logger.debug("Validator found " + errors.getErrorCount() + " errors"); + } + else { + logger.debug("Validator found no errors"); + } + } + } + + + /** + * Reject the given field with the given error code if the value is empty. + *

An 'empty' value in this context means either null or + * the empty string "". + *

The object whose field is being validated does not need to be passed + * in because the {@link Errors} instance can resolve field values by itself + * (it will usually hold an internal reference to the target object). + * @param errors the Errors instance to register errors on + * @param field the field name to check + * @param errorCode the error code, interpretable as message key + */ + public static void rejectIfEmpty(Errors errors, String field, String errorCode) { + rejectIfEmpty(errors, field, errorCode, null, null); + } + + /** + * Reject the given field with the given error code and default message + * if the value is empty. + *

An 'empty' value in this context means either null or + * the empty string "". + *

The object whose field is being validated does not need to be passed + * in because the {@link Errors} instance can resolve field values by itself + * (it will usually hold an internal reference to the target object). + * @param errors the Errors instance to register errors on + * @param field the field name to check + * @param errorCode error code, interpretable as message key + * @param defaultMessage fallback default message + */ + public static void rejectIfEmpty(Errors errors, String field, String errorCode, String defaultMessage) { + rejectIfEmpty(errors, field, errorCode, null, defaultMessage); + } + + /** + * Reject the given field with the given error codea nd error arguments + * if the value is empty. + *

An 'empty' value in this context means either null or + * the empty string "". + *

The object whose field is being validated does not need to be passed + * in because the {@link Errors} instance can resolve field values by itself + * (it will usually hold an internal reference to the target object). + * @param errors the Errors instance to register errors on + * @param field the field name to check + * @param errorCode the error code, interpretable as message key + * @param errorArgs the error arguments, for argument binding via MessageFormat + * (can be null) + */ + public static void rejectIfEmpty(Errors errors, String field, String errorCode, Object[] errorArgs) { + rejectIfEmpty(errors, field, errorCode, errorArgs, null); + } + + /** + * Reject the given field with the given error code, error arguments + * and default message if the value is empty. + *

An 'empty' value in this context means either null or + * the empty string "". + *

The object whose field is being validated does not need to be passed + * in because the {@link Errors} instance can resolve field values by itself + * (it will usually hold an internal reference to the target object). + * @param errors the Errors instance to register errors on + * @param field the field name to check + * @param errorCode the error code, interpretable as message key + * @param errorArgs the error arguments, for argument binding via MessageFormat + * (can be null) + * @param defaultMessage fallback default message + */ + public static void rejectIfEmpty( + Errors errors, String field, String errorCode, Object[] errorArgs, String defaultMessage) { + + Assert.notNull(errors, "Errors object must not be null"); + Object value = errors.getFieldValue(field); + if (value == null || !StringUtils.hasLength(value.toString())) { + errors.rejectValue(field, errorCode, errorArgs, defaultMessage); + } + } + + /** + * Reject the given field with the given error code if the value is empty + * or just contains whitespace. + *

An 'empty' value in this context means either null, + * the empty string "", or consisting wholly of whitespace. + *

The object whose field is being validated does not need to be passed + * in because the {@link Errors} instance can resolve field values by itself + * (it will usually hold an internal reference to the target object). + * @param errors the Errors instance to register errors on + * @param field the field name to check + * @param errorCode the error code, interpretable as message key + */ + public static void rejectIfEmptyOrWhitespace(Errors errors, String field, String errorCode) { + rejectIfEmptyOrWhitespace(errors, field, errorCode, null, null); + } + + /** + * Reject the given field with the given error code and default message + * if the value is empty or just contains whitespace. + *

An 'empty' value in this context means either null, + * the empty string "", or consisting wholly of whitespace. + *

The object whose field is being validated does not need to be passed + * in because the {@link Errors} instance can resolve field values by itself + * (it will usually hold an internal reference to the target object). + * @param errors the Errors instance to register errors on + * @param field the field name to check + * @param errorCode the error code, interpretable as message key + * @param defaultMessage fallback default message + */ + public static void rejectIfEmptyOrWhitespace( + Errors errors, String field, String errorCode, String defaultMessage) { + + rejectIfEmptyOrWhitespace(errors, field, errorCode, null, defaultMessage); + } + + /** + * Reject the given field with the given error code and error arguments + * if the value is empty or just contains whitespace. + *

An 'empty' value in this context means either null, + * the empty string "", or consisting wholly of whitespace. + *

The object whose field is being validated does not need to be passed + * in because the {@link Errors} instance can resolve field values by itself + * (it will usually hold an internal reference to the target object). + * @param errors the Errors instance to register errors on + * @param field the field name to check + * @param errorCode the error code, interpretable as message key + * @param errorArgs the error arguments, for argument binding via MessageFormat + * (can be null) + */ + public static void rejectIfEmptyOrWhitespace( + Errors errors, String field, String errorCode, Object[] errorArgs) { + + rejectIfEmptyOrWhitespace(errors, field, errorCode, errorArgs, null); + } + + /** + * Reject the given field with the given error code, error arguments + * and default message if the value is empty or just contains whitespace. + *

An 'empty' value in this context means either null, + * the empty string "", or consisting wholly of whitespace. + *

The object whose field is being validated does not need to be passed + * in because the {@link Errors} instance can resolve field values by itself + * (it will usually hold an internal reference to the target object). + * @param errors the Errors instance to register errors on + * @param field the field name to check + * @param errorCode the error code, interpretable as message key + * @param errorArgs the error arguments, for argument binding via MessageFormat + * (can be null) + * @param defaultMessage fallback default message + */ + public static void rejectIfEmptyOrWhitespace( + Errors errors, String field, String errorCode, Object[] errorArgs, String defaultMessage) { + + Assert.notNull(errors, "Errors object must not be null"); + Object value = errors.getFieldValue(field); + if (value == null ||!StringUtils.hasText(value.toString())) { + errors.rejectValue(field, errorCode, errorArgs, defaultMessage); + } + } + +} Index: 3rdParty_sources/spring/org/springframework/validation/Validator.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/validation/Validator.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/validation/Validator.java 17 Aug 2012 15:16:04 -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.validation; + +/** + * A validator for application-specific objects. + * + *

This interface is totally divorced from any infrastructure + * or context; that is to say it is not coupled to validating + * only objects in the web tier, the data-access tier, or the + * whatever-tier. As such it is amenable to being used in any layer + * of an application, and supports the encapsulation of validation + * logic as first-class citizens in their own right. + * + *

Find below a simple but complete Validator + * implementation, which validates that the various {@link String} + * properties of a UserLogin instance are not empty + * (that is they are not null and do not consist + * wholly of whitespace), and that any password that is present is + * at least 'MINIMUM_PASSWORD_LENGTH' characters in length. + * + *

 public class UserLoginValidator implements Validator {
+ * 
+ *    private static final int MINIMUM_PASSWORD_LENGTH = 6;
+ * 
+ *    public boolean supports(Class clazz) {
+ *       return UserLogin.class.isAssignableFrom(clazz);
+ *    }
+ * 
+ *    public void validate(Object target, Errors errors) {
+ *       ValidationUtils.rejectIfEmptyOrWhitespace(errors, "userName", "field.required");
+ *       ValidationUtils.rejectIfEmptyOrWhitespace(errors, "password", "field.required");
+ *       UserLogin login = (UserLogin) target;
+ *       if (login.getPassword() != null
+ *             && login.getPassword().trim().length() < MINIMUM_PASSWORD_LENGTH) {
+ *          errors.rejectValue("password", "field.min.length",
+ *                new Object[]{Integer.valueOf(MINIMUM_PASSWORD_LENGTH)},
+ *                "The password must be at least [" + MINIMUM_PASSWORD_LENGTH + "] characters in length.");
+ *       }
+ *    }
+ * }
+ * + *

See also the Spring reference manual for a fuller discussion of + * the Validator interface and it's role in a enterprise + * application. + * + * @author Rod Johnson + * @see Errors + * @see ValidationUtils + */ +public interface Validator { + + /** + * Can this {@link Validator} {@link #validate(Object, Errors) validate} + * instances of the supplied clazz? + *

This method is typically implemented like so: + *

return Foo.class.isAssignableFrom(clazz);
+ * (Where Foo is the class (or superclass) of the actual + * object instance that is to be {@link #validate(Object, Errors) validated}.) + * @param clazz the {@link Class} that this {@link Validator} is + * being asked if it can {@link #validate(Object, Errors) validate} + * @return true if this {@link Validator} can indeed + * {@link #validate(Object, Errors) validate} instances of the + * supplied clazz + */ + boolean supports(Class clazz); + + /** + * Validate the supplied target object, which must be + * of a {@link Class} for which the {@link #supports(Class)} method + * typically has (or would) return true. + *

The supplied {@link Errors errors} instance can be used to report + * any resulting validation errors. + * @param target the object that is to be validated (can be null) + * @param errors contextual state about the validation process (never null) + * @see ValidationUtils + */ + void validate(Object target, Errors errors); + +} Index: 3rdParty_sources/spring/org/springframework/validation/package.html =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/validation/package.html,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/validation/package.html 17 Aug 2012 15:16:04 -0000 1.1 @@ -0,0 +1,8 @@ + + + +Provides data binding and validation functionality, +for usage in business and/or UI layers. + + + Index: 3rdParty_sources/spring/org/springframework/validation/support/BindingAwareModelMap.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/validation/support/BindingAwareModelMap.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/validation/support/BindingAwareModelMap.java 17 Aug 2012 15:16:05 -0000 1.1 @@ -0,0 +1,64 @@ +/* + * 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.validation.support; + +import java.util.Map; +import java.util.Set; + +import org.springframework.ui.ExtendedModelMap; +import org.springframework.validation.BindingResult; + +/** + * Subclass of {@link org.springframework.ui.ExtendedModelMap} that + * automatically removes a {@link org.springframework.validation.BindingResult} + * object if the corresponding target attribute gets replaced. + * + *

Used by {@link org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter} + * and {@link org.springframework.web.portlet.mvc.annotation.AnnotationMethodHandlerAdapter}. + * + * @author Juergen Hoeller + * @since 2.5.6 + * @see org.springframework.validation.BindingResult + */ +public class BindingAwareModelMap extends ExtendedModelMap { + + public Object put(Object key, Object value) { + removeBindingResultIfNecessary(key, value); + return super.put(key, value); + } + + public void putAll(Map map) { + for (Map.Entry entry : (Set) map.entrySet()) { + removeBindingResultIfNecessary(entry.getKey(), entry.getValue()); + } + super.putAll(map); + } + + private void removeBindingResultIfNecessary(Object key, Object value) { + if (key instanceof String) { + String attributeName = (String) key; + if (!attributeName.startsWith(BindingResult.MODEL_KEY_PREFIX)) { + String bindingResultKey = BindingResult.MODEL_KEY_PREFIX + attributeName; + BindingResult bindingResult = (BindingResult) get(bindingResultKey); + if (bindingResult != null && bindingResult.getTarget() != value) { + remove(bindingResultKey); + } + } + } + } + +} Index: 3rdParty_sources/spring/org/springframework/validation/support/package.html =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/validation/support/package.html,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/validation/support/package.html 17 Aug 2012 15:16:05 -0000 1.1 @@ -0,0 +1,7 @@ + + + +Support classes for handling validation results. + + + Index: 3rdParty_sources/spring/org/springframework/web/HttpRequestHandler.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/web/HttpRequestHandler.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/web/HttpRequestHandler.java 17 Aug 2012 15:16:12 -0000 1.1 @@ -0,0 +1,90 @@ +/* + * 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.web; + +import java.io.IOException; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +/** + * Plain handler interface for components that process HTTP requests, + * analogous to a Servlet. Only declares {@link javax.servlet.ServletException} + * and {@link java.io.IOException}, to allow for usage within any + * {@link javax.servlet.http.HttpServlet}}. This interface is ssentially the + * direct equivalent of an HttpServlet, reduced to a central handle method. + * + *

The easiest way to expose an HttpRequestHandler bean in Spring style + * is to define it in Spring's root web application context and define + * an {@link org.springframework.web.context.support.HttpRequestHandlerServlet} + * in web.xml, pointing at the target HttpRequestHandler bean + * through its servlet-name which needs to match the target bean name. + * + *

Supported as a handler type within Spring's + * {@link org.springframework.web.servlet.DispatcherServlet}, being able + * to interact with the dispatcher's advanced mapping and interception + * facilities. This is the recommended way of exposing an HttpRequestHandler, + * while keeping the handler implementations free of direct dependencies + * on a DispatcherServlet environment. + * + *

Typically implemented to generate binary responses directly, + * with no separate view resource involved. This differentiates it from a + * {@link org.springframework.web.servlet.mvc.Controller} within Spring's Web MVC + * framework. The lack of a {@link org.springframework.web.servlet.ModelAndView} + * return value gives a clearer signature to callers other than the + * DispatcherServlet, indicating that there will never be a view to render. + * + *

As of Spring 2.0, Spring's HTTP-based remote exporters, such as + * {@link org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter} + * and {@link org.springframework.remoting.caucho.HessianServiceExporter}, + * implement this interface rather than the more extensive Controller interface, + * for minimal dependencies on Spring-specific web infrastructure. + * + *

Note that HttpRequestHandlers may optionally implement the + * {@link org.springframework.web.servlet.mvc.LastModified} interface, + * just like Controllers can, provided that they run within Spring's + * DispatcherServlet. However, this is usually not necessary, since + * HttpRequestHandlers typically only support POST requests to begin with. + * Alternatively, a handler may implement the "If-Modified-Since" HTTP + * header processing manually within its handle method. + * + * @author Juergen Hoeller + * @since 2.0 + * @see org.springframework.web.context.support.HttpRequestHandlerServlet + * @see org.springframework.web.servlet.DispatcherServlet + * @see org.springframework.web.servlet.ModelAndView + * @see org.springframework.web.servlet.mvc.Controller + * @see org.springframework.web.servlet.mvc.LastModified + * @see org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter + * @see org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter + * @see org.springframework.remoting.caucho.HessianServiceExporter + * @see org.springframework.remoting.caucho.BurlapServiceExporter + */ +public interface HttpRequestHandler { + + /** + * Process the given request, generating a response. + * @param request current HTTP request + * @param response current HTTP response + * @throws ServletException in case of general errors + * @throws IOException in case of I/O errors + */ + void handleRequest(HttpServletRequest request, HttpServletResponse response) + throws ServletException, IOException; + +} Index: 3rdParty_sources/spring/org/springframework/web/HttpRequestMethodNotSupportedException.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/web/HttpRequestMethodNotSupportedException.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/web/HttpRequestMethodNotSupportedException.java 17 Aug 2012 15:16:12 -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.web; + +import javax.servlet.ServletException; + +/** + * Exception thrown when a request handler does not support a + * specific request method. + * + * @author Juergen Hoeller + * @since 2.0 + */ +public class HttpRequestMethodNotSupportedException extends ServletException { + + private String method; + + private String[] supportedMethods; + + + /** + * Create a new HttpRequestMethodNotSupportedException. + * @param method the unsupported HTTP request method + */ + public HttpRequestMethodNotSupportedException(String method) { + this(method, (String[]) null); + } + + /** + * Create a new HttpRequestMethodNotSupportedException. + * @param method the unsupported HTTP request method + * @param supportedMethods the actually supported HTTP methods + */ + public HttpRequestMethodNotSupportedException(String method, String[] supportedMethods) { + this(method, supportedMethods, "Request method '" + method + "' not supported"); + } + + /** + * Create a new HttpRequestMethodNotSupportedException. + * @param method the unsupported HTTP request method + * @param msg the detail message + */ + public HttpRequestMethodNotSupportedException(String method, String msg) { + this(method, null, msg); + } + + /** + * Create a new HttpRequestMethodNotSupportedException. + * @param method the unsupported HTTP request method + * @param supportedMethods the actually supported HTTP methods + * @param msg the detail message + */ + public HttpRequestMethodNotSupportedException(String method, String[] supportedMethods, String msg) { + super(msg); + this.method = method; + this.supportedMethods = supportedMethods; + } + + + /** + * Return the HTTP request method that caused the failure. + */ + public String getMethod() { + return this.method; + } + + /** + * Return the actually supported HTTP methods, if known. + */ + public String[] getSupportedMethods() { + return this.supportedMethods; + } + +} Index: 3rdParty_sources/spring/org/springframework/web/HttpSessionRequiredException.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/web/HttpSessionRequiredException.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/web/HttpSessionRequiredException.java 17 Aug 2012 15:16:12 -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.web; + +import javax.servlet.ServletException; + +/** + * Exception thrown when an HTTP request handler requires a pre-existing session. + * + * @author Juergen Hoeller + * @since 2.0 + */ +public class HttpSessionRequiredException extends ServletException { + + /** + * Create a new HttpSessionRequiredException. + * @param msg the detail message + */ + public HttpSessionRequiredException(String msg) { + super(msg); + } + +} Index: 3rdParty_sources/spring/org/springframework/web/package.html =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/web/package.html,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/web/package.html 17 Aug 2012 15:16:12 -0000 1.1 @@ -0,0 +1,8 @@ + + + +Common, generic interfaces that define minimal boundary points +between Spring's web infrastructure and other framework modules. + + + Index: 3rdParty_sources/spring/org/springframework/web/context/ConfigurableWebApplicationContext.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/web/context/ConfigurableWebApplicationContext.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/web/context/ConfigurableWebApplicationContext.java 17 Aug 2012 15:16:18 -0000 1.1 @@ -0,0 +1,95 @@ +/* + * 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.web.context; + +import javax.servlet.ServletConfig; +import javax.servlet.ServletContext; + +import org.springframework.context.ConfigurableApplicationContext; + +/** + * Interface to be implemented by configurable web application contexts. + * Supported by {@link ContextLoader} and + * {@link org.springframework.web.servlet.FrameworkServlet}. + * + *

Note: The setters of this interface need to be called before an + * invocation of the {@link #refresh} method inherited from + * {@link org.springframework.context.ConfigurableApplicationContext}. + * They do not cause an initialization of the context on their own. + * + * @author Juergen Hoeller + * @since 05.12.2003 + * @see #refresh + * @see ContextLoader#createWebApplicationContext + * @see org.springframework.web.servlet.FrameworkServlet#createWebApplicationContext + */ +public interface ConfigurableWebApplicationContext extends WebApplicationContext, ConfigurableApplicationContext { + + /** + * Set the ServletContext for this web application context. + *

Does not cause an initialization of the context: refresh needs to be + * called after the setting of all configuration properties. + * @see #refresh() + */ + void setServletContext(ServletContext servletContext); + + /** + * Set the ServletConfig for this web application context. + * Only called for a WebApplicationContext that belongs to a specific Servlet. + * @see #refresh() + */ + void setServletConfig(ServletConfig servletConfig); + + /** + * Return the ServletConfig for this web application context, if any. + */ + ServletConfig getServletConfig(); + + /** + * Set the namespace for this web application context, + * to be used for building a default context config location. + * The root web application context does not have a namespace. + */ + void setNamespace(String namespace); + + /** + * Return the namespace for this web application context, if any. + */ + String getNamespace(); + + /** + * Set the config locations for this web application context in init-param style, + * i.e. with distinct locations separated by commas, semicolons or whitespace. + *

If not set, the implementation is supposed to use a default for the + * given namespace or the root web application context, as appropriate. + */ + void setConfigLocation(String configLocation); + + /** + * Set the config locations for this web application context. + *

If not set, the implementation is supposed to use a default for the + * given namespace or the root web application context, as appropriate. + */ + void setConfigLocations(String[] configLocations); + + /** + * Return the config locations for this web application context, + * or null if none specified. + */ + String[] getConfigLocations(); + +} Index: 3rdParty_sources/spring/org/springframework/web/context/ContextLoader.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/web/context/ContextLoader.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/web/context/ContextLoader.java 17 Aug 2012 15:16:18 -0000 1.1 @@ -0,0 +1,386 @@ +/* + * 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.web.context; + +import java.io.IOException; +import java.util.Map; +import java.util.Properties; + +import javax.servlet.ServletContext; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import org.springframework.beans.BeanUtils; +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.access.BeanFactoryLocator; +import org.springframework.beans.factory.access.BeanFactoryReference; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextException; +import org.springframework.context.access.ContextSingletonBeanFactoryLocator; +import org.springframework.core.CollectionFactory; +import org.springframework.core.io.ClassPathResource; +import org.springframework.core.io.support.PropertiesLoaderUtils; +import org.springframework.util.ClassUtils; + +/** + * Performs the actual initialization work for the root application context. + * Called by {@link ContextLoaderListener} and {@link ContextLoaderServlet}. + * + *

Looks for a {@link #CONTEXT_CLASS_PARAM "contextClass"} parameter + * at the web.xml context-param level to specify the context + * class type, falling back to the default of + * {@link org.springframework.web.context.support.XmlWebApplicationContext} + * if not found. With the default ContextLoader implementation, any context class + * specified needs to implement the ConfigurableWebApplicationContext interface. + * + *

Processes a {@link #CONFIG_LOCATION_PARAM "contextConfigLocation"} + * context-param and passes its value to the context instance, parsing it into + * potentially multiple file paths which can be separated by any number of + * commas and spaces, e.g. "WEB-INF/applicationContext1.xml, + * WEB-INF/applicationContext2.xml". Ant-style path patterns are supported as well, + * e.g. "WEB-INF/*Context.xml,WEB-INF/spring*.xml" or "WEB-INF/**/*Context.xml". + * If not explicitly specified, the context implementation is supposed to use a + * default location (with XmlWebApplicationContext: "/WEB-INF/applicationContext.xml"). + * + *

Note: In case of multiple config locations, later bean definitions will + * override ones defined in previously loaded files, at least when using one of + * Spring's default ApplicationContext implementations. This can be leveraged + * to deliberately override certain bean definitions via an extra XML file. + * + *

Above and beyond loading the root application context, this class + * can optionally load or obtain and hook up a shared parent context to + * the root application context. See the + * {@link #loadParentContext(ServletContext)} method for more information. + * + * @author Juergen Hoeller + * @author Colin Sampaleanu + * @author Sam Brannen + * @since 17.02.2003 + * @see ContextLoaderListener + * @see ContextLoaderServlet + * @see ConfigurableWebApplicationContext + * @see org.springframework.web.context.support.XmlWebApplicationContext + */ +public class ContextLoader { + + /** + * Config param for the root WebApplicationContext implementation class to + * use: "contextClass" + */ + public static final String CONTEXT_CLASS_PARAM = "contextClass"; + + /** + * Name of servlet context parameter (i.e., "contextConfigLocation") + * that can specify the config location for the root context, falling back + * to the implementation's default otherwise. + * @see org.springframework.web.context.support.XmlWebApplicationContext#DEFAULT_CONFIG_LOCATION + */ + public static final String CONFIG_LOCATION_PARAM = "contextConfigLocation"; + + /** + * Optional servlet context parameter (i.e., "locatorFactorySelector") + * used only when obtaining a parent context using the default implementation + * of {@link #loadParentContext(ServletContext servletContext)}. + * Specifies the 'selector' used in the + * {@link ContextSingletonBeanFactoryLocator#getInstance(String selector)} + * method call, which is used to obtain the BeanFactoryLocator instance from + * which the parent context is obtained. + *

The default is classpath*:beanRefContext.xml, + * matching the default applied for the + * {@link ContextSingletonBeanFactoryLocator#getInstance()} method. + * Supplying the "parentContextKey" parameter is sufficient in this case. + */ + public static final String LOCATOR_FACTORY_SELECTOR_PARAM = "locatorFactorySelector"; + + /** + * Optional servlet context parameter (i.e., "parentContextKey") + * used only when obtaining a parent context using the default implementation + * of {@link #loadParentContext(ServletContext servletContext)}. + * Specifies the 'factoryKey' used in the + * {@link BeanFactoryLocator#useBeanFactory(String factoryKey)} method call, + * obtaining the parent application context from the BeanFactoryLocator instance. + *

Supplying this "parentContextKey" parameter is sufficient when relying + * on the default classpath*:beanRefContext.xml selector for + * candidate factory references. + */ + public static final String LOCATOR_FACTORY_KEY_PARAM = "parentContextKey"; + + /** + * Name of the class path resource (relative to the ContextLoader class) + * that defines ContextLoader's default strategy names. + */ + private static final String DEFAULT_STRATEGIES_PATH = "ContextLoader.properties"; + + + private static final Properties defaultStrategies; + + static { + // Load default strategy implementations from properties file. + // This is currently strictly internal and not meant to be customized + // by application developers. + try { + ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, ContextLoader.class); + defaultStrategies = PropertiesLoaderUtils.loadProperties(resource); + } + catch (IOException ex) { + throw new IllegalStateException("Could not load 'ContextLoader.properties': " + ex.getMessage()); + } + } + + + private static final Log logger = LogFactory.getLog(ContextLoader.class); + + /** + * Map from (thread context) ClassLoader to WebApplicationContext. + * Often just holding one reference - if the ContextLoader class is + * deployed in the web app ClassLoader itself! + */ + private static final Map currentContextPerThread = CollectionFactory.createConcurrentMapIfPossible(1); + + /** + * The root WebApplicationContext instance that this loader manages. + */ + private WebApplicationContext context; + + /** + * Holds BeanFactoryReference when loading parent factory via + * ContextSingletonBeanFactoryLocator. + */ + private BeanFactoryReference parentContextRef; + + + /** + * Initialize Spring's web application context for the given servlet context, + * according to the "{@link #CONTEXT_CLASS_PARAM contextClass}" and + * "{@link #CONFIG_LOCATION_PARAM contextConfigLocation}" context-params. + * @param servletContext current servlet context + * @return the new WebApplicationContext + * @throws IllegalStateException if there is already a root application context present + * @throws BeansException if the context failed to initialize + * @see #CONTEXT_CLASS_PARAM + * @see #CONFIG_LOCATION_PARAM + */ + public WebApplicationContext initWebApplicationContext(ServletContext servletContext) + throws IllegalStateException, BeansException { + + if (servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null) { + throw new IllegalStateException( + "Cannot initialize context because there is already a root application context present - " + + "check whether you have multiple ContextLoader* definitions in your web.xml!"); + } + + servletContext.log("Initializing Spring root WebApplicationContext"); + if (logger.isInfoEnabled()) { + logger.info("Root WebApplicationContext: initialization started"); + } + long startTime = System.currentTimeMillis(); + + try { + // Determine parent for root web application context, if any. + ApplicationContext parent = loadParentContext(servletContext); + + // Store context in local instance variable, to guarantee that + // it is available on ServletContext shutdown. + this.context = createWebApplicationContext(servletContext, parent); + servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context); + currentContextPerThread.put(Thread.currentThread().getContextClassLoader(), this.context); + + if (logger.isDebugEnabled()) { + logger.debug("Published root WebApplicationContext as ServletContext attribute with name [" + + WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE + "]"); + } + if (logger.isInfoEnabled()) { + long elapsedTime = System.currentTimeMillis() - startTime; + logger.info("Root WebApplicationContext: initialization completed in " + elapsedTime + " ms"); + } + + return this.context; + } + catch (RuntimeException ex) { + logger.error("Context initialization failed", ex); + servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, ex); + throw ex; + } + catch (Error err) { + logger.error("Context initialization failed", err); + servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, err); + throw err; + } + } + + /** + * Instantiate the root WebApplicationContext for this loader, either the + * default context class or a custom context class if specified. + *

This implementation expects custom contexts to implement the + * {@link ConfigurableWebApplicationContext} interface. + * Can be overridden in subclasses. + *

In addition, {@link #customizeContext} gets called prior to refreshing the + * context, allowing subclasses to perform custom modifications to the context. + * @param servletContext current servlet context + * @param parent the parent ApplicationContext to use, or null if none + * @return the root WebApplicationContext + * @throws BeansException if the context couldn't be initialized + * @see ConfigurableWebApplicationContext + */ + protected WebApplicationContext createWebApplicationContext( + ServletContext servletContext, ApplicationContext parent) throws BeansException { + + Class contextClass = determineContextClass(servletContext); + if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) { + throw new ApplicationContextException("Custom context class [" + contextClass.getName() + + "] is not of type [" + ConfigurableWebApplicationContext.class.getName() + "]"); + } + + ConfigurableWebApplicationContext wac = + (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass); + wac.setParent(parent); + wac.setServletContext(servletContext); + wac.setConfigLocation(servletContext.getInitParameter(CONFIG_LOCATION_PARAM)); + customizeContext(servletContext, wac); + wac.refresh(); + + return wac; + } + + /** + * Return the WebApplicationContext implementation class to use, either the + * default XmlWebApplicationContext or a custom context class if specified. + * @param servletContext current servlet context + * @return the WebApplicationContext implementation class to use + * @throws ApplicationContextException if the context class couldn't be loaded + * @see #CONTEXT_CLASS_PARAM + * @see org.springframework.web.context.support.XmlWebApplicationContext + */ + protected Class determineContextClass(ServletContext servletContext) throws ApplicationContextException { + String contextClassName = servletContext.getInitParameter(CONTEXT_CLASS_PARAM); + if (contextClassName != null) { + try { + return ClassUtils.forName(contextClassName); + } + catch (ClassNotFoundException ex) { + throw new ApplicationContextException( + "Failed to load custom context class [" + contextClassName + "]", ex); + } + } + else { + contextClassName = defaultStrategies.getProperty(WebApplicationContext.class.getName()); + try { + return ClassUtils.forName(contextClassName, ContextLoader.class.getClassLoader()); + } + catch (ClassNotFoundException ex) { + throw new ApplicationContextException( + "Failed to load default context class [" + contextClassName + "]", ex); + } + } + } + + /** + * Customize the {@link ConfigurableWebApplicationContext} created by this + * ContextLoader after config locations have been supplied to the context + * but before the context is refreshed. + *

The default implementation is empty but can be overridden in subclasses + * to customize the application context. + * @param servletContext the current servlet context + * @param applicationContext the newly created application context + * @see #createWebApplicationContext(ServletContext, ApplicationContext) + */ + protected void customizeContext( + ServletContext servletContext, ConfigurableWebApplicationContext applicationContext) { + } + + /** + * Template method with default implementation (which may be overridden by a + * subclass), to load or obtain an ApplicationContext instance which will be + * used as the parent context of the root WebApplicationContext. If the + * return value from the method is null, no parent context is set. + *

The main reason to load a parent context here is to allow multiple root + * web application contexts to all be children of a shared EAR context, or + * alternately to also share the same parent context that is visible to + * EJBs. For pure web applications, there is usually no need to worry about + * having a parent context to the root web application context. + *

The default implementation uses + * {@link org.springframework.context.access.ContextSingletonBeanFactoryLocator}, + * configured via {@link #LOCATOR_FACTORY_SELECTOR_PARAM} and + * {@link #LOCATOR_FACTORY_KEY_PARAM}, to load a parent context + * which will be shared by all other users of ContextsingletonBeanFactoryLocator + * which also use the same configuration parameters. + * @param servletContext current servlet context + * @return the parent application context, or null if none + * @throws BeansException if the context couldn't be initialized + * @see org.springframework.context.access.ContextSingletonBeanFactoryLocator + */ + protected ApplicationContext loadParentContext(ServletContext servletContext) + throws BeansException { + + ApplicationContext parentContext = null; + String locatorFactorySelector = servletContext.getInitParameter(LOCATOR_FACTORY_SELECTOR_PARAM); + String parentContextKey = servletContext.getInitParameter(LOCATOR_FACTORY_KEY_PARAM); + + if (parentContextKey != null) { + // locatorFactorySelector may be null, indicating the default "classpath*:beanRefContext.xml" + BeanFactoryLocator locator = ContextSingletonBeanFactoryLocator.getInstance(locatorFactorySelector); + if (logger.isDebugEnabled()) { + logger.debug("Getting parent context definition: using parent context key of '" + + parentContextKey + "' with BeanFactoryLocator"); + } + this.parentContextRef = locator.useBeanFactory(parentContextKey); + parentContext = (ApplicationContext) this.parentContextRef.getFactory(); + } + + return parentContext; + } + + /** + * Close Spring's web application context for the given servlet context. If + * the default {@link #loadParentContext(ServletContext)} implementation, + * which uses ContextSingletonBeanFactoryLocator, has loaded any shared + * parent context, release one reference to that shared parent context. + *

If overriding {@link #loadParentContext(ServletContext)}, you may have + * to override this method as well. + * @param servletContext the ServletContext that the WebApplicationContext runs in + */ + public void closeWebApplicationContext(ServletContext servletContext) { + servletContext.log("Closing Spring root WebApplicationContext"); + try { + if (this.context instanceof ConfigurableWebApplicationContext) { + ((ConfigurableWebApplicationContext) this.context).close(); + } + } + finally { + currentContextPerThread.remove(Thread.currentThread().getContextClassLoader()); + servletContext.removeAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE); + if (this.parentContextRef != null) { + this.parentContextRef.release(); + } + } + } + + + /** + * Obtain the Spring root web application context for the current thread + * (i.e. for the current thread's context ClassLoader, which needs to be + * the web application's ClassLoader). + * @return the current root web application context, or null + * if none found + * @see org.springframework.web.context.support.SpringBeanAutowiringSupport + */ + public static WebApplicationContext getCurrentWebApplicationContext() { + return (WebApplicationContext) currentContextPerThread.get(Thread.currentThread().getContextClassLoader()); + } + +} Index: 3rdParty_sources/spring/org/springframework/web/context/ContextLoader.properties =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/web/context/ContextLoader.properties,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/web/context/ContextLoader.properties 17 Aug 2012 15:16:18 -0000 1.1 @@ -0,0 +1,5 @@ +# Default WebApplicationContext implementation class for ContextLoader. +# Used as fallback when no explicit context implementation has been specified as context-param. +# Not meant to be customized by application developers. + +org.springframework.web.context.WebApplicationContext=org.springframework.web.context.support.XmlWebApplicationContext Index: 3rdParty_sources/spring/org/springframework/web/context/ContextLoaderListener.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/web/context/ContextLoaderListener.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/web/context/ContextLoaderListener.java 17 Aug 2012 15:16:18 -0000 1.1 @@ -0,0 +1,74 @@ +/* + * 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.web.context; + +import javax.servlet.ServletContextEvent; +import javax.servlet.ServletContextListener; + +/** + * Bootstrap listener to start up Spring's root {@link WebApplicationContext}. + * Simply delegates to {@link ContextLoader}. + * + *

This listener should be registered after + * {@link org.springframework.web.util.Log4jConfigListener} + * in web.xml, if the latter is used. + * + * @author Juergen Hoeller + * @since 17.02.2003 + * @see ContextLoaderServlet + * @see org.springframework.web.util.Log4jConfigListener + */ +public class ContextLoaderListener implements ServletContextListener { + + private ContextLoader contextLoader; + + + /** + * Initialize the root web application context. + */ + public void contextInitialized(ServletContextEvent event) { + this.contextLoader = createContextLoader(); + this.contextLoader.initWebApplicationContext(event.getServletContext()); + } + + /** + * Create the ContextLoader to use. Can be overridden in subclasses. + * @return the new ContextLoader + */ + protected ContextLoader createContextLoader() { + return new ContextLoader(); + } + + /** + * Return the ContextLoader used by this listener. + * @return the current ContextLoader + */ + public ContextLoader getContextLoader() { + return this.contextLoader; + } + + + /** + * Close the root web application context. + */ + public void contextDestroyed(ServletContextEvent event) { + if (this.contextLoader != null) { + this.contextLoader.closeWebApplicationContext(event.getServletContext()); + } + } + +} Index: 3rdParty_sources/spring/org/springframework/web/context/ContextLoaderServlet.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/web/context/ContextLoaderServlet.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/web/context/ContextLoaderServlet.java 17 Aug 2012 15:16:18 -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.web.context; + +import java.io.IOException; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +/** + * Bootstrap servlet to start up Spring's root {@link WebApplicationContext}. + * Simply delegates to {@link ContextLoader}. + * + *

This servlet should have a lower load-on-startup value + * in web.xml than any servlets that access the root web + * application context. + * + *

Note that this class has been deprecated for containers implementing + * Servlet API 2.4 or higher, in favor of {@link ContextLoaderListener}.
+ * According to Servlet 2.4, listeners must be initialized before load-on-startup + * servlets. Many Servlet 2.3 containers already enforce this behavior. If you + * use such a container, this servlet can be replaced with ContextLoaderListener. + * + *

Servlet 2.3 containers known to work with bootstrap listeners are: + *

    + *
  • Apache Tomcat 4.x+ + *
  • Jetty 4.x+ + *
  • Resin 2.1.8+ + *
  • Orion 2.0.2+ + *
  • BEA WebLogic 8.1 SP3 + *
+ * For working with any of them, ContextLoaderListener is recommended. + * + *

Servlet 2.3 containers known not to work with bootstrap listeners are: + *

    + *
  • BEA WebLogic up to 8.1 SP2 + *
  • IBM WebSphere 5.x + *
  • Oracle OC4J 9.0.3 + *
+ * If you happen to work with such a server, this servlet has to be used. + * + *

So unfortunately, the only context initialization option that is compatible + * with all Servlet 2.3 containers is this servlet. + * + *

Note that a startup failure of this servlet will not stop the rest of the + * web application from starting, in contrast to a listener failure. This can + * lead to peculiar side effects if other servlets get started that depend on + * initialization of the root web application context. + * + * @author Juergen Hoeller + * @author Darren Davison + * @see ContextLoaderListener + * @see org.springframework.web.util.Log4jConfigServlet + */ +public class ContextLoaderServlet extends HttpServlet { + + private ContextLoader contextLoader; + + + /** + * Initialize the root web application context. + */ + public void init() throws ServletException { + this.contextLoader = createContextLoader(); + this.contextLoader.initWebApplicationContext(getServletContext()); + } + + /** + * Create the ContextLoader to use. Can be overridden in subclasses. + * @return the new ContextLoader + */ + protected ContextLoader createContextLoader() { + return new ContextLoader(); + } + + /** + * Return the ContextLoader used by this servlet. + * @return the current ContextLoader + */ + public ContextLoader getContextLoader() { + return this.contextLoader; + } + + + /** + * Close the root web application context. + */ + public void destroy() { + if (this.contextLoader != null) { + this.contextLoader.closeWebApplicationContext(getServletContext()); + } + } + + + /** + * This should never even be called since no mapping to this servlet should + * ever be created in web.xml. That's why a correctly invoked Servlet 2.3 + * listener is much more appropriate for initialization work ;-) + */ + public void service(HttpServletRequest request, HttpServletResponse response) throws IOException { + getServletContext().log( + "Attempt to call service method on ContextLoaderServlet as [" + + request.getRequestURI() + "] was ignored"); + response.sendError(HttpServletResponse.SC_BAD_REQUEST); + } + + + public String getServletInfo() { + return "ContextLoaderServlet for Servlet API 2.3 " + + "(deprecated in favor of ContextLoaderListener for Servlet API 2.4)"; + } + +} Index: 3rdParty_sources/spring/org/springframework/web/context/ServletConfigAware.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/web/context/ServletConfigAware.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/web/context/ServletConfigAware.java 17 Aug 2012 15:16:18 -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.web.context; + +import javax.servlet.ServletConfig; + +/** + * Interface to be implemented by any object that wishes to be notified + * of the ServletConfig (typically determined by the WebApplicationContext) + * that it runs in. + * + *

Only satisfied if actually running within a Servlet-specific + * WebApplicationContext. If this callback interface is encountered + * elsewhere, an exception will be thrown on bean creation. + * + * @author Juergen Hoeller + * @since 2.0 + * @see ServletContextAware + */ +public interface ServletConfigAware { + + /** + * Set the ServletConfig that this object runs in. + *

Invoked after population of normal bean properties but before an init + * callback like InitializingBean's afterPropertiesSet or a + * custom init-method. Invoked after ApplicationContextAware's + * setApplicationContext. + * @param servletConfig ServletConfig object to be used by this object + * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet + * @see org.springframework.context.ApplicationContextAware#setApplicationContext + */ + void setServletConfig(ServletConfig servletConfig); + +} Index: 3rdParty_sources/spring/org/springframework/web/context/ServletContextAware.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/web/context/ServletContextAware.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/web/context/ServletContextAware.java 17 Aug 2012 15:16:18 -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.web.context; + +import javax.servlet.ServletContext; + +/** + * Interface to be implemented by any object that wishes to be notified + * of the ServletContext (typically determined by the WebApplicationContext) + * that it runs in. + * + * @author Juergen Hoeller + * @since 12.03.2004 + * @see ServletConfigAware + */ +public interface ServletContextAware { + + /** + * Set the ServletContext that this object runs in. + *

Invoked after population of normal bean properties but before an init + * callback like InitializingBean's afterPropertiesSet or a + * custom init-method. Invoked after ApplicationContextAware's + * setApplicationContext. + * @param servletContext ServletContext object to be used by this object + * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet + * @see org.springframework.context.ApplicationContextAware#setApplicationContext + */ + void setServletContext(ServletContext servletContext); + +} Index: 3rdParty_sources/spring/org/springframework/web/context/WebApplicationContext.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/web/context/WebApplicationContext.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/web/context/WebApplicationContext.java 17 Aug 2012 15:16:18 -0000 1.1 @@ -0,0 +1,81 @@ +/* + * 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.web.context; + +import javax.servlet.ServletContext; + +import org.springframework.context.ApplicationContext; + +/** + * Interface to provide configuration for a web application. This is read-only while + * the application is running, but may be reloaded if the implementation supports this. + * + *

This interface adds a getServletContext method to the generic ApplicationContext + * interface, and defines a well-known application attribute name that the root + * context must be bound to in the bootstrap process. + * + *

Like generic application contexts, web application contexts are hierarchical. + * There is a single root context per application, while each servlet in the application + * (including a dispatcher servlet in the MVC framework) has its own child context. + * + *

In addition to standard application context lifecycle capabilities, + * WebApplicationContext implementations need to detect ServletContextAware + * beans and invoke the setServletContext method accordingly. + * + * @author Rod Johnson + * @author Juergen Hoeller + * @since January 19, 2001 + * @see ServletContextAware#setServletContext + */ +public interface WebApplicationContext extends ApplicationContext { + + /** + * Context attribute to bind root WebApplicationContext to on successful startup. + *

Note: If the startup of the root context fails, this attribute can contain + * an exception or error as value. Use WebApplicationContextUtils for convenient + * lookup of the root WebApplicationContext. + * @see org.springframework.web.context.support.WebApplicationContextUtils#getWebApplicationContext + * @see org.springframework.web.context.support.WebApplicationContextUtils#getRequiredWebApplicationContext + */ + String ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE = WebApplicationContext.class.getName() + ".ROOT"; + + + /** + * Scope identifier for request scope: "request". + * Supported in addition to the standard scopes "singleton" and "prototype". + */ + String SCOPE_REQUEST = "request"; + + /** + * Scope identifier for session scope: "session". + * Supported in addition to the standard scopes "singleton" and "prototype". + */ + String SCOPE_SESSION = "session"; + + /** + * Scope identifier for global session scope: "globalSession". + * Supported in addition to the standard scopes "singleton" and "prototype". + */ + String SCOPE_GLOBAL_SESSION = "globalSession"; + + + /** + * Return the standard Servlet API ServletContext for this application. + */ + ServletContext getServletContext(); + +} Index: 3rdParty_sources/spring/org/springframework/web/context/package.html =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/web/context/package.html,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/web/context/package.html 17 Aug 2012 15:16:18 -0000 1.1 @@ -0,0 +1,8 @@ + + + +Contains a variant of the application context interface for web applications, +and the ContextLoaderListener that bootstraps a root web application context. + + + Index: 3rdParty_sources/spring/org/springframework/web/context/request/AbstractRequestAttributes.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/web/context/request/AbstractRequestAttributes.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/web/context/request/AbstractRequestAttributes.java 17 Aug 2012 15:16:14 -0000 1.1 @@ -0,0 +1,104 @@ +/* + * 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.web.context.request; + +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.Map; + +import org.springframework.util.Assert; + +/** + * Abstract support class for RequestAttributes implementations, + * offering a request completion mechanism for request-specific destruction + * callbacks and for updating accessed session attributes. + * + * @author Juergen Hoeller + * @since 2.0 + * @see #requestCompleted() + */ +public abstract class AbstractRequestAttributes implements RequestAttributes { + + /** Map from attribute name String to destruction callback Runnable */ + protected final Map requestDestructionCallbacks = new LinkedHashMap(8); + + private volatile boolean requestActive = true; + + + /** + * Signal that the request has been completed. + *

Executes all request destruction callbacks and updates the + * session attributes that have been accessed during request processing. + */ + public void requestCompleted() { + executeRequestDestructionCallbacks(); + updateAccessedSessionAttributes(); + this.requestActive = false; + } + + /** + * Determine whether the original request is still active. + * @see #requestCompleted() + */ + protected final boolean isRequestActive() { + return this.requestActive; + } + + /** + * Register the given callback as to be executed after request completion. + * @param name the name of the attribute to register the callback for + * @param callback the callback to be executed for destruction + */ + protected final void registerRequestDestructionCallback(String name, Runnable callback) { + Assert.notNull(name, "Name must not be null"); + Assert.notNull(callback, "Callback must not be null"); + synchronized (this.requestDestructionCallbacks) { + this.requestDestructionCallbacks.put(name, callback); + } + } + + /** + * Remove the request destruction callback for the specified attribute, if any. + * @param name the name of the attribute to remove the callback for + */ + protected final void removeRequestDestructionCallback(String name) { + Assert.notNull(name, "Name must not be null"); + synchronized (this.requestDestructionCallbacks) { + this.requestDestructionCallbacks.remove(name); + } + } + + /** + * Execute all callbacks that have been registered for execution + * after request completion. + */ + private void executeRequestDestructionCallbacks() { + synchronized (this.requestDestructionCallbacks) { + for (Iterator it = this.requestDestructionCallbacks.values().iterator(); it.hasNext();) { + ((Runnable) it.next()).run(); + } + this.requestDestructionCallbacks.clear(); + } + } + + /** + * Update all session attributes that have been accessed during request processing, + * to expose their potentially updated state to the underlying session manager. + */ + protected abstract void updateAccessedSessionAttributes(); + +} Index: 3rdParty_sources/spring/org/springframework/web/context/request/AbstractRequestAttributesScope.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/web/context/request/AbstractRequestAttributesScope.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/web/context/request/AbstractRequestAttributesScope.java 17 Aug 2012 15:16:14 -0000 1.1 @@ -0,0 +1,77 @@ +/* + * 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.web.context.request; + +import org.springframework.beans.factory.ObjectFactory; +import org.springframework.beans.factory.config.Scope; + +/** + * Abstract {@link Scope} implementation that reads from a particular scope + * in the current thread-bound {@link RequestAttributes} object. + * + *

Subclasses simply need to implement {@link #getScope()} to instruct + * this class which {@link RequestAttributes} scope to read attributes from. + * + *

Subclasses may wish to override the {@link #get} and {@link #remove} + * methods to add synchronization around the call back into this super class. + * + * @author Rod Johnson + * @author Juergen Hoeller + * @author Rob Harrop + * @since 2.0 + */ +public abstract class AbstractRequestAttributesScope implements Scope { + + public Object get(String name, ObjectFactory objectFactory) { + RequestAttributes attributes = RequestContextHolder.currentRequestAttributes(); + Object scopedObject = attributes.getAttribute(name, getScope()); + if (scopedObject == null) { + scopedObject = objectFactory.getObject(); + attributes.setAttribute(name, scopedObject, getScope()); + } + return scopedObject; + } + + public Object remove(String name) { + RequestAttributes attributes = RequestContextHolder.currentRequestAttributes(); + Object scopedObject = attributes.getAttribute(name, getScope()); + if (scopedObject != null) { + attributes.removeAttribute(name, getScope()); + return scopedObject; + } + else { + return null; + } + } + + public void registerDestructionCallback(String name, Runnable callback) { + RequestAttributes attributes = RequestContextHolder.currentRequestAttributes(); + attributes.registerDestructionCallback(name, callback, getScope()); + } + + + /** + * Template method that determines the actual target scope. + * @return the target scope, in the form of an appropriate + * {@link RequestAttributes} constant + * @see RequestAttributes#SCOPE_REQUEST + * @see RequestAttributes#SCOPE_SESSION + * @see RequestAttributes#SCOPE_GLOBAL_SESSION + */ + protected abstract int getScope(); + +} Index: 3rdParty_sources/spring/org/springframework/web/context/request/FacesRequestAttributes.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/web/context/request/FacesRequestAttributes.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/web/context/request/FacesRequestAttributes.java 17 Aug 2012 15:16:14 -0000 1.1 @@ -0,0 +1,149 @@ +/* + * 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.web.context.request; + +import java.lang.reflect.Method; +import java.util.Map; + +import javax.faces.context.ExternalContext; +import javax.faces.context.FacesContext; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import org.springframework.util.Assert; +import org.springframework.util.ReflectionUtils; +import org.springframework.util.StringUtils; +import org.springframework.web.util.WebUtils; + +/** + * {@link RequestAttributes} adapter for a JSF {@link javax.faces.context.FacesContext}. + * Used as default in a JSF environment, wrapping the current FacesContext. + * + *

NOTE: In contrast to {@link ServletRequestAttributes}, this variant does + * not support destruction callbacks for scoped attributes, neither for the + * request scope nor for the session scope. If you rely on such implicit destruction + * callbacks, consider defining a Spring {@link RequestContextListener} in your + * web.xml. + * + * @author Juergen Hoeller + * @since 2.5.2 + * @see javax.faces.context.FacesContext#getExternalContext() + * @see javax.faces.context.ExternalContext#getRequestMap() + * @see javax.faces.context.ExternalContext#getSessionMap() + * @see RequestContextHolder#currentRequestAttributes() + */ +public class FacesRequestAttributes implements RequestAttributes { + + /** + * We'll create a lot of these objects, so we don't want a new logger every time. + */ + private static final Log logger = LogFactory.getLog(FacesRequestAttributes.class); + + private final FacesContext facesContext; + + + /** + * Create a new FacesRequestAttributes adapter for the given FacesContext. + * @param facesContext the current FacesContext + * @see javax.faces.context.FacesContext#getCurrentInstance() + */ + public FacesRequestAttributes(FacesContext facesContext) { + Assert.notNull(facesContext, "FacesContext must not be null"); + this.facesContext = facesContext; + } + + + /** + * Return the JSF FacesContext that this adapter operates on. + */ + protected FacesContext getFacesContext() { + return this.facesContext; + } + + /** + * Return the JSF ExternalContext that this adapter operates on. + * @see javax.faces.context.FacesContext#getExternalContext() + */ + protected ExternalContext getExternalContext() { + return getFacesContext().getExternalContext(); + } + + /** + * Return the JSF attribute Map for the specified scope + * @param scope constant indicating request or session scope + * @return the Map representation of the attributes in the specified scope + * @see #SCOPE_REQUEST + * @see #SCOPE_SESSION + */ + protected Map getAttributeMap(int scope) { + if (scope == SCOPE_REQUEST) { + return getExternalContext().getRequestMap(); + } + else { + return getExternalContext().getSessionMap(); + } + } + + + public Object getAttribute(String name, int scope) { + return getAttributeMap(scope).get(name); + } + + public void setAttribute(String name, Object value, int scope) { + getAttributeMap(scope).put(name, value); + } + + public void removeAttribute(String name, int scope) { + getAttributeMap(scope).remove(name); + } + + public String[] getAttributeNames(int scope) { + return StringUtils.toStringArray(getAttributeMap(scope).entrySet()); + } + + public void registerDestructionCallback(String name, Runnable callback, int scope) { + if (logger.isWarnEnabled()) { + logger.warn("Could not register destruction callback [" + callback + "] for attribute '" + name + + "' because FacesRequestAttributes does not support such callbacks"); + } + } + + public String getSessionId() { + Object session = getExternalContext().getSession(true); + try { + // Both HttpSession and PortletSession have a getId() method. + Method getIdMethod = session.getClass().getMethod("getId", new Class[0]); + return ReflectionUtils.invokeMethod(getIdMethod, session).toString(); + } + catch (NoSuchMethodException ex) { + throw new IllegalStateException("Session object [" + session + "] does not have a getId() method"); + } + } + + public Object getSessionMutex() { + // Enforce presence of a session first to allow listeners + // to create the mutex attribute, if any. + Object session = getExternalContext().getSession(true); + Object mutex = getExternalContext().getSessionMap().get(WebUtils.SESSION_MUTEX_ATTRIBUTE); + if (mutex == null) { + mutex = session; + } + return mutex; + } + +} Index: 3rdParty_sources/spring/org/springframework/web/context/request/FacesWebRequest.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/web/context/request/FacesWebRequest.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/web/context/request/FacesWebRequest.java 17 Aug 2012 15:16:15 -0000 1.1 @@ -0,0 +1,117 @@ +/* + * 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.web.context.request; + +import java.security.Principal; +import java.util.Locale; +import java.util.Map; + +import javax.faces.context.ExternalContext; +import javax.faces.context.FacesContext; + +import org.springframework.util.StringUtils; + +/** + * {@link WebRequest} adapter for a JSF {@link javax.faces.context.FacesContext}. + * + * @author Juergen Hoeller + * @since 2.5.2 + */ +public class FacesWebRequest extends FacesRequestAttributes implements NativeWebRequest { + + /** + * Create a new FacesWebRequest adapter for the given FacesContext. + * @param facesContext the current FacesContext + * @see javax.faces.context.FacesContext#getCurrentInstance() + */ + public FacesWebRequest(FacesContext facesContext) { + super(facesContext); + } + + + public Object getNativeRequest() { + return getExternalContext().getRequest(); + } + + public Object getNativeResponse() { + return getExternalContext().getResponse(); + } + + + public String getParameter(String paramName) { + return (String) getExternalContext().getRequestParameterMap().get(paramName); + } + + public String[] getParameterValues(String paramName) { + return (String[]) getExternalContext().getRequestParameterValuesMap().get(paramName); + } + + public Map getParameterMap() { + return getExternalContext().getRequestParameterMap(); + } + + public Locale getLocale() { + return getFacesContext().getExternalContext().getRequestLocale(); + } + + public String getContextPath() { + return getFacesContext().getExternalContext().getRequestContextPath(); + } + + public String getRemoteUser() { + return getFacesContext().getExternalContext().getRemoteUser(); + } + + public Principal getUserPrincipal() { + return getFacesContext().getExternalContext().getUserPrincipal(); + } + + public boolean isUserInRole(String role) { + return getFacesContext().getExternalContext().isUserInRole(role); + } + + public boolean isSecure() { + return false; + } + + public boolean checkNotModified(long lastModifiedTimestamp) { + return false; + } + + + public String getDescription(boolean includeClientInfo) { + ExternalContext externalContext = getExternalContext(); + StringBuffer buffer = new StringBuffer(); + buffer.append("context=").append(externalContext.getRequestContextPath()); + if (includeClientInfo) { + Object session = externalContext.getSession(false); + if (session != null) { + buffer.append(";session=").append(getSessionId()); + } + String user = externalContext.getRemoteUser(); + if (StringUtils.hasLength(user)) { + buffer.append(";user=").append(user); + } + } + return buffer.toString(); + } + + public String toString() { + return "FacesWebRequest: " + getDescription(true); + } + +} Index: 3rdParty_sources/spring/org/springframework/web/context/request/Log4jNestedDiagnosticContextInterceptor.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/web/context/request/Log4jNestedDiagnosticContextInterceptor.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/web/context/request/Log4jNestedDiagnosticContextInterceptor.java 17 Aug 2012 15:16:14 -0000 1.1 @@ -0,0 +1,91 @@ +/* + * 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.web.context.request; + +import org.apache.log4j.Logger; +import org.apache.log4j.NDC; + +import org.springframework.ui.ModelMap; + +/** + * Request logging interceptor that adds a request context message to the + * Log4J nested diagnostic context (NDC) before the request is processed, + * removing it again after the request is processed. + * + * @author Juergen Hoeller + * @since 2.5 + * @see org.apache.log4j.NDC#push(String) + * @see org.apache.log4j.NDC#pop() + */ +public class Log4jNestedDiagnosticContextInterceptor implements WebRequestInterceptor { + + /** Logger available to subclasses */ + protected final Logger log4jLogger = Logger.getLogger(getClass()); + + private boolean includeClientInfo = false; + + + /** + * Set whether or not the session id and user name should be included + * in the log message. + */ + public void setIncludeClientInfo(boolean includeClientInfo) { + this.includeClientInfo = includeClientInfo; + } + + /** + * Return whether or not the session id and user name should be included + * in the log message. + */ + protected boolean isIncludeClientInfo() { + return this.includeClientInfo; + } + + + /** + * Adds a message the Log4J NDC before the request is processed. + */ + public void preHandle(WebRequest request) throws Exception { + NDC.push(getNestedDiagnosticContextMessage(request)); + } + + /** + * Determine the message to be pushed onto the Log4J nested diagnostic context. + *

Default is the request object's getDescription result. + * @param request current HTTP request + * @return the message to be pushed onto the Log4J NDC + * @see WebRequest#getDescription + * @see #isIncludeClientInfo() + */ + protected String getNestedDiagnosticContextMessage(WebRequest request) { + return request.getDescription(isIncludeClientInfo()); + } + + public void postHandle(WebRequest request, ModelMap model) throws Exception { + } + + /** + * Removes the log message from the Log4J NDC after the request is processed. + */ + public void afterCompletion(WebRequest request, Exception ex) throws Exception { + NDC.pop(); + if (NDC.getDepth() == 0) { + NDC.remove(); + } + } + +} Index: 3rdParty_sources/spring/org/springframework/web/context/request/NativeWebRequest.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/web/context/request/NativeWebRequest.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/web/context/request/NativeWebRequest.java 17 Aug 2012 15:16:15 -0000 1.1 @@ -0,0 +1,47 @@ +/* + * 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.web.context.request; + +/** + * Extension of the {@link WebRequest} interface, exposing the + * native request and response objects in a generic fashion. + * + *

Mainly intended for framework-internal usage, + * in particular for generic argument resolution code. + * + * @author Juergen Hoeller + * @since 2.5.2 + */ +public interface NativeWebRequest extends WebRequest { + + /** + * Return the underlying native request object, if available. + * @see javax.servlet.http.HttpServletRequest + * @see javax.portlet.ActionRequest + * @see javax.portlet.RenderRequest + */ + Object getNativeRequest(); + + /** + * Return the underlying native response object, if available. + * @see javax.servlet.http.HttpServletResponse + * @see javax.portlet.ActionResponse + * @see javax.portlet.RenderResponse + */ + Object getNativeResponse(); + +} Index: 3rdParty_sources/spring/org/springframework/web/context/request/RequestAttributes.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/web/context/request/RequestAttributes.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/web/context/request/RequestAttributes.java 17 Aug 2012 15:16:14 -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.web.context.request; + +/** + * Abstraction for accessing attribute objects associated with a request. + * Supports access to request-scoped attributes as well as to session-scoped + * attributes, with the optional notion of a "global session". + * + *

Can be implemented for any kind of request/session mechanism, + * in particular for servlet requests and portlet requests. + * + * @author Juergen Hoeller + * @since 2.0 + * @see ServletRequestAttributes + * @see org.springframework.web.portlet.context.PortletRequestAttributes + */ +public interface RequestAttributes { + + /** + * Constant that indicates request scope. + */ + int SCOPE_REQUEST = 0; + + /** + * Constant that indicates session scope. + *

This preferably refers to a locally isolated session, if such + * a distinction is available (for example, in a Portlet environment). + * Else, it simply refers to the common session. + */ + int SCOPE_SESSION = 1; + + /** + * Constant that indicates global session scope. + *

This explicitly refers to a globally shared session, if such + * a distinction is available (for example, in a Portlet environment). + * Else, it simply refers to the common session. + */ + int SCOPE_GLOBAL_SESSION = 2; + + + /** + * Return the value for the scoped attribute of the given name, if any. + * @param name the name of the attribute + * @param scope the scope identifier + * @return the current attribute value, or null if not found + */ + Object getAttribute(String name, int scope); + + /** + * Set the value for the scoped attribute of the given name, + * replacing an existing value (if any). + * @param name the name of the attribute + * @param scope the scope identifier + * @param value the value for the attribute + */ + void setAttribute(String name, Object value, int scope); + + /** + * Remove the scoped attribute of the given name, if it exists. + *

Note that an implementation should also remove a registered destruction + * callback for the specified attribute, if any. It does, however, not + * need to execute a registered destruction callback in this case, + * since the object will be destroyed by the caller (if appropriate). + * @param name the name of the attribute + * @param scope the scope identifier + */ + void removeAttribute(String name, int scope); + + /** + * Retrieve the names of all attributes in the scope. + * @param scope the scope identifier + * @return the attribute names as String array + */ + String[] getAttributeNames(int scope); + + /** + * Register a callback to be executed on destruction of the + * specified attribute in the given scope. + *

Implementations should do their best to execute the callback + * at the appropriate time: that is, at request completion or session + * termination, respectively. If such a callback is not supported by the + * underlying runtime environment, the callback must be ignored + * and a corresponding warning should be logged. + *

Note that 'destruction' usually corresponds to destruction of the + * entire scope, not to the individual attribute having been explicitly + * removed by the application. If an attribute gets removed via this + * facade's {@link #removeAttribute(String, int)} method, any registered + * destruction callback should be disabled as well, assuming that the + * removed object will be reused or manually destroyed. + * @param name the name of the attribute to register the callback for + * @param callback the destruction callback to be executed + * @param scope the scope identifier + */ + void registerDestructionCallback(String name, Runnable callback, int scope); + + /** + * Return an id for the current underlying session. + * @return the session id as String (never null + */ + String getSessionId(); + + /** + * Expose the best available mutex for the underlying session: + * that is, an object to synchronize on for the underlying session. + * @return the session mutex to use (never null + */ + Object getSessionMutex(); + +} Index: 3rdParty_sources/spring/org/springframework/web/context/request/RequestContextHolder.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/web/context/request/RequestContextHolder.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/web/context/request/RequestContextHolder.java 17 Aug 2012 15:16:14 -0000 1.1 @@ -0,0 +1,145 @@ +/* + * 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.web.context.request; + +import javax.faces.context.FacesContext; + +import org.springframework.core.NamedInheritableThreadLocal; +import org.springframework.core.NamedThreadLocal; +import org.springframework.util.ClassUtils; + +/** + * Holder class to expose the web request in the form of a thread-bound + * {@link RequestAttributes} object. + * + *

Use {@link RequestContextListener} or + * {@link org.springframework.web.filter.RequestContextFilter} to expose + * the current web request. Note that + * {@link org.springframework.web.servlet.DispatcherServlet} and + * {@link org.springframework.web.portlet.DispatcherPortlet} already + * expose the current request by default. + * + * @author Juergen Hoeller + * @author Rod Johnson + * @since 2.0 + * @see RequestContextListener + * @see org.springframework.web.filter.RequestContextFilter + * @see org.springframework.web.servlet.DispatcherServlet + * @see org.springframework.web.portlet.DispatcherPortlet + */ +public abstract class RequestContextHolder { + + private static final boolean jsfPresent = + ClassUtils.isPresent("javax.faces.context.FacesContext", RequestContextHolder.class.getClassLoader()); + + private static final ThreadLocal requestAttributesHolder = new NamedThreadLocal("Request attributes"); + + private static final ThreadLocal inheritableRequestAttributesHolder = + new NamedInheritableThreadLocal("Request context"); + + + /** + * Reset the RequestAttributes for the current thread. + */ + public static void resetRequestAttributes() { + requestAttributesHolder.set(null); + inheritableRequestAttributesHolder.set(null); + } + + /** + * Bind the given RequestAttributes to the current thread, + * not exposing it as inheritable for child threads. + * @param attributes the RequestAttributes to expose + * @see #setRequestAttributes(RequestAttributes, boolean) + */ + public static void setRequestAttributes(RequestAttributes attributes) { + setRequestAttributes(attributes, false); + } + + /** + * Bind the given RequestAttributes to the current thread. + * @param attributes the RequestAttributes to expose + * @param inheritable whether to expose the RequestAttributes as inheritable + * for child threads (using an {@link java.lang.InheritableThreadLocal}) + */ + public static void setRequestAttributes(RequestAttributes attributes, boolean inheritable) { + if (inheritable) { + inheritableRequestAttributesHolder.set(attributes); + requestAttributesHolder.set(null); + } + else { + requestAttributesHolder.set(attributes); + inheritableRequestAttributesHolder.set(null); + } + } + + /** + * Return the RequestAttributes currently bound to the thread. + * @return the RequestAttributes currently bound to the thread, + * or null if none bound + */ + public static RequestAttributes getRequestAttributes() { + RequestAttributes attributes = (RequestAttributes) requestAttributesHolder.get(); + if (attributes == null) { + attributes = (RequestAttributes) inheritableRequestAttributesHolder.get(); + } + return attributes; + } + + /** + * Return the RequestAttributes currently bound to the thread. + *

Exposes the previously bound RequestAttributes instance, if any. + * Falls back to the current JSF FacesContext, if any. + * @return the RequestAttributes currently bound to the thread + * @throws IllegalStateException if no RequestAttributes object + * is bound to the current thread + * @see #setRequestAttributes + * @see ServletRequestAttributes + * @see FacesRequestAttributes + * @see javax.faces.context.FacesContext#getCurrentInstance() + */ + public static RequestAttributes currentRequestAttributes() throws IllegalStateException { + RequestAttributes attributes = getRequestAttributes(); + if (attributes == null) { + if (jsfPresent) { + attributes = FacesRequestAttributesFactory.getFacesRequestAttributes(); + } + if (attributes == null) { + throw new IllegalStateException("No thread-bound request found: " + + "Are you referring to request attributes outside of an actual web request, " + + "or processing a request outside of the originally receiving thread? " + + "If you are actually operating within a web request and still receive this message, " + + "your code is probably running outside of DispatcherServlet/DispatcherPortlet: " + + "In this case, use RequestContextListener or RequestContextFilter to expose the current request."); + } + } + return attributes; + } + + + /** + * Inner class to avoid hard-coded JSF dependency. + */ + private static class FacesRequestAttributesFactory { + + public static RequestAttributes getFacesRequestAttributes() { + FacesContext facesContext = FacesContext.getCurrentInstance(); + return (facesContext != null ? new FacesRequestAttributes(facesContext) : null); + } + } + +} Index: 3rdParty_sources/spring/org/springframework/web/context/request/RequestContextListener.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/web/context/request/RequestContextListener.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/web/context/request/RequestContextListener.java 17 Aug 2012 15:16:14 -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.web.context.request; + +import javax.servlet.ServletRequestEvent; +import javax.servlet.ServletRequestListener; +import javax.servlet.http.HttpServletRequest; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import org.springframework.context.i18n.LocaleContextHolder; + +/** + * Servlet 2.4+ listener that exposes the request to the current thread, + * through both {@link org.springframework.context.i18n.LocaleContextHolder} and + * {@link RequestContextHolder}. To be registered as listener in web.xml. + * + *

Alternatively, Spring's {@link org.springframework.web.filter.RequestContextFilter} + * and Spring's {@link org.springframework.web.servlet.DispatcherServlet} also expose + * the same request context to the current thread. In contrast to this listener, + * advanced options are available there (e.g. "threadContextInheritable"). + * + *

This listener is mainly for use with third-party servlets, e.g. the JSF FacesServlet. + * Within Spring's own web support, DispatcherServlet's processing is perfectly sufficient. + * + * @author Juergen Hoeller + * @since 2.0 + * @see javax.servlet.ServletRequestListener + * @see org.springframework.context.i18n.LocaleContextHolder + * @see org.springframework.web.context.request.RequestContextHolder + * @see org.springframework.web.filter.RequestContextFilter + * @see org.springframework.web.servlet.DispatcherServlet + */ +public class RequestContextListener implements ServletRequestListener { + + private static final String REQUEST_ATTRIBUTES_ATTRIBUTE = + RequestContextListener.class.getName() + ".REQUEST_ATTRIBUTES"; + + /** Logger available to subclasses */ + protected final Log logger = LogFactory.getLog(getClass()); + + + public void requestInitialized(ServletRequestEvent requestEvent) { + if (!(requestEvent.getServletRequest() instanceof HttpServletRequest)) { + throw new IllegalArgumentException( + "Request is not an HttpServletRequest: " + requestEvent.getServletRequest()); + } + HttpServletRequest request = (HttpServletRequest) requestEvent.getServletRequest(); + ServletRequestAttributes attributes = new ServletRequestAttributes(request); + request.setAttribute(REQUEST_ATTRIBUTES_ATTRIBUTE, attributes); + LocaleContextHolder.setLocale(request.getLocale()); + RequestContextHolder.setRequestAttributes(attributes); + if (logger.isDebugEnabled()) { + logger.debug("Bound request context to thread: " + request); + } + } + + public void requestDestroyed(ServletRequestEvent requestEvent) { + ServletRequestAttributes attributes = + (ServletRequestAttributes) requestEvent.getServletRequest().getAttribute(REQUEST_ATTRIBUTES_ATTRIBUTE); + ServletRequestAttributes threadAttributes = + (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); + if (threadAttributes != null) { + // We're assumably within the original request thread... + if (attributes == null) { + attributes = threadAttributes; + } + RequestContextHolder.resetRequestAttributes(); + LocaleContextHolder.resetLocaleContext(); + } + if (attributes != null) { + attributes.requestCompleted(); + if (logger.isDebugEnabled()) { + logger.debug("Cleared thread-bound request context: " + requestEvent.getServletRequest()); + } + } + } + +} Index: 3rdParty_sources/spring/org/springframework/web/context/request/RequestScope.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/web/context/request/RequestScope.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/web/context/request/RequestScope.java 17 Aug 2012 15:16:15 -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.web.context.request; + +/** + * Request-backed {@link org.springframework.beans.factory.config.Scope} + * implementation. + * + *

Relies on a thread-bound {@link RequestAttributes} instance, which + * can be exported through {@link RequestContextListener}, + * {@link org.springframework.web.filter.RequestContextFilter} or + * {@link org.springframework.web.servlet.DispatcherServlet}. + * + *

This Scope will also work for Portlet environments, + * through an alternate RequestAttributes implementation + * (as exposed out-of-the-box by Spring's + * {@link org.springframework.web.portlet.DispatcherPortlet}. + * + * @author Rod Johnson + * @author Juergen Hoeller + * @author Rob Harrop + * @since 2.0 + * @see RequestContextHolder#currentRequestAttributes() + * @see RequestAttributes#SCOPE_REQUEST + * @see RequestContextListener + * @see org.springframework.web.filter.RequestContextFilter + * @see org.springframework.web.servlet.DispatcherServlet + * @see org.springframework.web.portlet.DispatcherPortlet + */ +public class RequestScope extends AbstractRequestAttributesScope { + + protected int getScope() { + return RequestAttributes.SCOPE_REQUEST; + } + + /** + * There is no conversation id concept for a request, so this method + * returns null. + */ + public String getConversationId() { + return null; + } + +} Index: 3rdParty_sources/spring/org/springframework/web/context/request/ServletRequestAttributes.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/web/context/request/ServletRequestAttributes.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/web/context/request/ServletRequestAttributes.java 17 Aug 2012 15:16:15 -0000 1.1 @@ -0,0 +1,273 @@ +/* + * 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.web.context.request; + +import java.io.Serializable; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpSession; +import javax.servlet.http.HttpSessionBindingEvent; +import javax.servlet.http.HttpSessionBindingListener; + +import org.springframework.util.Assert; +import org.springframework.util.StringUtils; +import org.springframework.web.util.WebUtils; + +/** + * Servlet-based implementation of the {@link RequestAttributes} interface. + * + *

Accesses objects from servlet request and HTTP session scope, + * with no distinction between "session" and "global session". + * + * @author Juergen Hoeller + * @since 2.0 + * @see javax.servlet.ServletRequest#getAttribute + * @see javax.servlet.http.HttpSession#getAttribute + */ +public class ServletRequestAttributes extends AbstractRequestAttributes { + + /** + * Constant identifying the {@link String} prefixed to the name of a + * destruction callback when it is stored in a {@link HttpSession}. + */ + public static final String DESTRUCTION_CALLBACK_NAME_PREFIX = + ServletRequestAttributes.class.getName() + ".DESTRUCTION_CALLBACK."; + + + private final HttpServletRequest request; + + private volatile HttpSession session; + + private final Map sessionAttributesToUpdate = new HashMap(); + + + /** + * Create a new ServletRequestAttributes instance for the given request. + * @param request current HTTP request + */ + public ServletRequestAttributes(HttpServletRequest request) { + Assert.notNull(request, "Request must not be null"); + this.request = request; + } + + + /** + * Exposes the native {@link HttpServletRequest} that we're wrapping. + */ + public final HttpServletRequest getRequest() { + return this.request; + } + + /** + * Exposes the {@link HttpSession} that we're wrapping. + * @param allowCreate whether to allow creation of a new session if none exists yet + */ + protected final HttpSession getSession(boolean allowCreate) { + if (isRequestActive()) { + return this.request.getSession(allowCreate); + } + else { + // Access through stored session reference, if any... + if (this.session == null && allowCreate) { + throw new IllegalStateException( + "No session found and request already completed - cannot create new session!"); + } + return this.session; + } + } + + + public Object getAttribute(String name, int scope) { + if (scope == SCOPE_REQUEST) { + if (!isRequestActive()) { + throw new IllegalStateException( + "Cannot ask for request attribute - request is not active anymore!"); + } + return this.request.getAttribute(name); + } + else { + HttpSession session = getSession(false); + if (session != null) { + try { + Object value = session.getAttribute(name); + if (value != null) { + synchronized (this.sessionAttributesToUpdate) { + this.sessionAttributesToUpdate.put(name, value); + } + } + return value; + } + catch (IllegalStateException ex) { + // Session invalidated - shouldn't usually happen. + } + } + return null; + } + } + + public void setAttribute(String name, Object value, int scope) { + if (scope == SCOPE_REQUEST) { + if (!isRequestActive()) { + throw new IllegalStateException( + "Cannot set request attribute - request is not active anymore!"); + } + this.request.setAttribute(name, value); + } + else { + HttpSession session = getSession(true); + synchronized (this.sessionAttributesToUpdate) { + this.sessionAttributesToUpdate.remove(name); + } + session.setAttribute(name, value); + } + } + + public void removeAttribute(String name, int scope) { + if (scope == SCOPE_REQUEST) { + if (isRequestActive()) { + this.request.removeAttribute(name); + removeRequestDestructionCallback(name); + } + } + else { + HttpSession session = getSession(false); + if (session != null) { + synchronized (this.sessionAttributesToUpdate) { + this.sessionAttributesToUpdate.remove(name); + } + try { + session.removeAttribute(name); + // Remove any registered destruction callback as well. + session.removeAttribute(DESTRUCTION_CALLBACK_NAME_PREFIX + name); + } + catch (IllegalStateException ex) { + // Session invalidated - shouldn't usually happen. + } + } + } + } + + public String[] getAttributeNames(int scope) { + if (scope == SCOPE_REQUEST) { + if (!isRequestActive()) { + throw new IllegalStateException( + "Cannot ask for request attributes - request is not active anymore!"); + } + return StringUtils.toStringArray(this.request.getAttributeNames()); + } + else { + HttpSession session = getSession(false); + if (session != null) { + try { + return StringUtils.toStringArray(session.getAttributeNames()); + } + catch (IllegalStateException ex) { + // Session invalidated - shouldn't usually happen. + } + } + return new String[0]; + } + } + + public void registerDestructionCallback(String name, Runnable callback, int scope) { + if (scope == SCOPE_REQUEST) { + registerRequestDestructionCallback(name, callback); + } + else { + registerSessionDestructionCallback(name, callback); + } + } + + public String getSessionId() { + return getSession(true).getId(); + } + + public Object getSessionMutex() { + return WebUtils.getSessionMutex(getSession(true)); + } + + + /** + * Update all accessed session attributes through session.setAttribute + * calls, explicitly indicating to the container that they might have been modified. + */ + protected void updateAccessedSessionAttributes() { + // Store session reference for access after request completion. + this.session = this.request.getSession(false); + // Update all affected session attributes. + synchronized (this.sessionAttributesToUpdate) { + if (this.session != null) { + try { + for (Iterator it = this.sessionAttributesToUpdate.entrySet().iterator(); it.hasNext();) { + Map.Entry entry = (Map.Entry) it.next(); + String name = (String) entry.getKey(); + Object newValue = entry.getValue(); + Object oldValue = this.session.getAttribute(name); + if (oldValue == newValue) { + this.session.setAttribute(name, newValue); + } + } + } + catch (IllegalStateException ex) { + // Session invalidated - shouldn't usually happen. + } + } + this.sessionAttributesToUpdate.clear(); + } + } + + /** + * Register the given callback as to be executed after session termination. + * @param name the name of the attribute to register the callback for + * @param callback the callback to be executed for destruction + */ + private void registerSessionDestructionCallback(String name, Runnable callback) { + HttpSession session = getSession(true); + session.setAttribute(DESTRUCTION_CALLBACK_NAME_PREFIX + name, + new DestructionCallbackBindingListener(callback)); + } + + + public String toString() { + return this.request.toString(); + } + + + /** + * Adapter that implements the Servlet 2.3 HttpSessionBindingListener + * interface, wrapping a session destruction callback. + */ + private static class DestructionCallbackBindingListener implements HttpSessionBindingListener, Serializable { + + private final Runnable destructionCallback; + + public DestructionCallbackBindingListener(Runnable destructionCallback) { + this.destructionCallback = destructionCallback; + } + + public void valueBound(HttpSessionBindingEvent event) { + } + + public void valueUnbound(HttpSessionBindingEvent event) { + this.destructionCallback.run(); + } + } + +} Index: 3rdParty_sources/spring/org/springframework/web/context/request/ServletWebRequest.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/web/context/request/ServletWebRequest.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/web/context/request/ServletWebRequest.java 17 Aug 2012 15:16:14 -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.web.context.request; + +import java.security.Principal; +import java.util.Locale; +import java.util.Map; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; + +import org.springframework.util.StringUtils; + +/** + * {@link WebRequest} adapter for an {@link javax.servlet.http.HttpServletRequest}. + * + * @author Juergen Hoeller + * @since 2.0 + */ +public class ServletWebRequest extends ServletRequestAttributes implements NativeWebRequest { + + private static final String HEADER_IF_MODIFIED_SINCE = "If-Modified-Since"; + + private static final String HEADER_LAST_MODIFIED = "Last-Modified"; + + + private HttpServletResponse response; + + private boolean notModified = false; + + + /** + * Create a new ServletWebRequest instance for the given request. + * @param request current HTTP request + */ + public ServletWebRequest(HttpServletRequest request) { + super(request); + } + + /** + * Create a new ServletWebRequest instance for the given request/response pair. + * @param request current HTTP request + * @param response current HTTP response (for automatic last-modified handling) + */ + public ServletWebRequest(HttpServletRequest request, HttpServletResponse response) { + super(request); + this.response = response; + } + + + /** + * Exposes the native {@link HttpServletRequest} that we're wrapping (if any). + */ + public final HttpServletResponse getResponse() { + return this.response; + } + + public Object getNativeRequest() { + return getRequest(); + } + + public Object getNativeResponse() { + return getResponse(); + } + + + public String getParameter(String paramName) { + return getRequest().getParameter(paramName); + } + + public String[] getParameterValues(String paramName) { + return getRequest().getParameterValues(paramName); + } + + public Map getParameterMap() { + return getRequest().getParameterMap(); + } + + public Locale getLocale() { + return getRequest().getLocale(); + } + + public String getContextPath() { + return getRequest().getContextPath(); + } + + public String getRemoteUser() { + return getRequest().getRemoteUser(); + } + + public Principal getUserPrincipal() { + return getRequest().getUserPrincipal(); + } + + public boolean isUserInRole(String role) { + return getRequest().isUserInRole(role); + } + + public boolean isSecure() { + return getRequest().isSecure(); + } + + + public boolean checkNotModified(long lastModifiedTimestamp) { + if (lastModifiedTimestamp >= 0 && !this.notModified && + (this.response == null || !this.response.containsHeader(HEADER_LAST_MODIFIED))) { + long ifModifiedSince = getRequest().getDateHeader(HEADER_IF_MODIFIED_SINCE); + this.notModified = (ifModifiedSince >= (lastModifiedTimestamp / 1000 * 1000)); + if (this.response != null) { + if (this.notModified) { + this.response.setStatus(HttpServletResponse.SC_NOT_MODIFIED); + } + else { + this.response.setDateHeader(HEADER_LAST_MODIFIED, lastModifiedTimestamp); + } + } + } + return this.notModified; + } + + public boolean isNotModified() { + return this.notModified; + } + + + public String getDescription(boolean includeClientInfo) { + HttpServletRequest request = getRequest(); + StringBuffer buffer = new StringBuffer(); + buffer.append("uri=").append(request.getRequestURI()); + if (includeClientInfo) { + String client = request.getRemoteAddr(); + if (StringUtils.hasLength(client)) { + buffer.append(";client=").append(client); + } + HttpSession session = request.getSession(false); + if (session != null) { + buffer.append(";session=").append(session.getId()); + } + String user = request.getRemoteUser(); + if (StringUtils.hasLength(user)) { + buffer.append(";user=").append(user); + } + } + return buffer.toString(); + } + + public String toString() { + return "ServletWebRequest: " + getDescription(true); + } + +} Index: 3rdParty_sources/spring/org/springframework/web/context/request/SessionScope.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/web/context/request/SessionScope.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/web/context/request/SessionScope.java 17 Aug 2012 15:16:14 -0000 1.1 @@ -0,0 +1,101 @@ +/* + * 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.web.context.request; + +import org.springframework.beans.factory.ObjectFactory; + +/** + * Session-backed {@link org.springframework.beans.factory.config.Scope} + * implementation. + * + *

Relies on a thread-bound {@link RequestAttributes} instance, which + * can be exported through {@link RequestContextListener}, + * {@link org.springframework.web.filter.RequestContextFilter} or + * {@link org.springframework.web.servlet.DispatcherServlet}. + * + *

This Scope will also work for Portlet environments, + * through an alternate RequestAttributes implementation + * (as exposed out-of-the-box by Spring's + * {@link org.springframework.web.portlet.DispatcherPortlet}. + * + * @author Rod Johnson + * @author Juergen Hoeller + * @author Rob Harrop + * @since 2.0 + * @see RequestContextHolder#currentRequestAttributes() + * @see RequestAttributes#SCOPE_SESSION + * @see RequestAttributes#SCOPE_GLOBAL_SESSION + * @see RequestContextListener + * @see org.springframework.web.filter.RequestContextFilter + * @see org.springframework.web.servlet.DispatcherServlet + * @see org.springframework.web.portlet.DispatcherPortlet + */ +public class SessionScope extends AbstractRequestAttributesScope { + + private final int scope; + + + /** + * Create a new SessionScope, storing attributes in a locally + * isolated session (or default session, if there is no distinction + * between a global session and a component-specific session). + */ + public SessionScope() { + this.scope = RequestAttributes.SCOPE_SESSION; + } + + /** + * Create a new SessionScope, specifying whether to store attributes + * in the global session, provided that such a distinction is available. + *

This distinction is important for Portlet environments, where there + * are two notions of a session: "portlet scope" and "application scope". + * If this flag is on, objects will be put into the "application scope" session; + * else they will end up in the "portlet scope" session (the typical default). + *

In a Servlet environment, this flag is effectively ignored. + * @param globalSession true in case of the global session as target; + * false in case of a component-specific session as target + * @see org.springframework.web.portlet.context.PortletRequestAttributes + * @see org.springframework.web.context.request.ServletRequestAttributes + */ + public SessionScope(boolean globalSession) { + this.scope = (globalSession ? RequestAttributes.SCOPE_GLOBAL_SESSION : RequestAttributes.SCOPE_SESSION); + } + + + protected int getScope() { + return this.scope; + } + + public String getConversationId() { + return RequestContextHolder.currentRequestAttributes().getSessionId(); + } + + public Object get(String name, ObjectFactory objectFactory) { + Object mutex = RequestContextHolder.currentRequestAttributes().getSessionMutex(); + synchronized (mutex) { + return super.get(name, objectFactory); + } + } + + public Object remove(String name) { + Object mutex = RequestContextHolder.currentRequestAttributes().getSessionMutex(); + synchronized (mutex) { + return super.remove(name); + } + } + +} Index: 3rdParty_sources/spring/org/springframework/web/context/request/WebRequest.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/web/context/request/WebRequest.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/web/context/request/WebRequest.java 17 Aug 2012 15:16:15 -0000 1.1 @@ -0,0 +1,129 @@ +/* + * 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.web.context.request; + +import java.security.Principal; +import java.util.Locale; +import java.util.Map; + +/** + * Generic interface for a web request. Mainly intended for generic web + * request interceptors, giving them access to general request metadata, + * not for actual handling of the request. + * + * @author Juergen Hoeller + * @since 2.0 + * @see WebRequestInterceptor + */ +public interface WebRequest extends RequestAttributes { + + /** + * Return the request parameter of the given name, or null if none. + *

Retrieves the first parameter value in case of a multi-value parameter. + * @see javax.servlet.http.HttpServletRequest#getParameter(String) + */ + String getParameter(String paramName); + + /** + * Return the request parameter values for the given parameter name, + * or null if none. + *

A single-value parameter will be exposed as an array with a single element. + * @see javax.servlet.http.HttpServletRequest#getParameterValues(String) + */ + String[] getParameterValues(String paramName); + + /** + * Return a immutable Map of the request parameters, with parameter names as map keys + * and parameter values as map values. The map values will be of type String array. + *

A single-value parameter will be exposed as an array with a single element. + * @see javax.servlet.http.HttpServletRequest#getParameterMap() + */ + Map getParameterMap(); + + /** + * Return the primary Locale for this request. + * @see javax.servlet.http.HttpServletRequest#getLocale() + */ + Locale getLocale(); + + /** + * Return the context path for this request + * (usually the base path that the current web application is mapped to). + * @see javax.servlet.http.HttpServletRequest#getContextPath() + */ + String getContextPath(); + + /** + * Return the remote user for this request, if any. + * @see javax.servlet.http.HttpServletRequest#getRemoteUser() + */ + String getRemoteUser(); + + /** + * Return the user principal for this request, if any. + * @see javax.servlet.http.HttpServletRequest#getUserPrincipal() + */ + Principal getUserPrincipal(); + + /** + * Determine whether the user is in the given role for this request. + * @see javax.servlet.http.HttpServletRequest#isUserInRole(String) + */ + boolean isUserInRole(String role); + + /** + * Return whether this request has been sent over a secure transport + * mechanism (such as SSL). + * @see javax.servlet.http.HttpServletRequest#isSecure() + */ + boolean isSecure(); + + /** + * Check whether the request qualifies as not modified given the + * supplied last-modified timestamp (as determined by the application). + *

This will also transparently set the appropriate response headers, + * for both the modified case and the not-modified case. + *

Typical usage: + *

+	 * public String myHandleMethod(WebRequest webRequest, Model model) {
+	 *   long lastModified = // application-specific calculation
+	 *   if (request.checkNotModified(lastModified)) {
+	 *     // shortcut exit - no further processing necessary
+	 *     return null;
+	 *   }
+	 *   // further request processing, actually building content
+	 *   model.addAttribute(...);
+	 *   return "myViewName";
+	 * }
+ * @param lastModifiedTimestamp the last-modified timestamp that + * the application determined for the underlying resource + * @return whether the request qualifies as not modified, + * allowing to abort request processing and relying on the response + * telling the client that the content has not been modified + */ + boolean checkNotModified(long lastModifiedTimestamp); + + /** + * Get a short description of this request, + * typically containing request URI and session id. + * @param includeClientInfo whether to include client-specific + * information such as session id and user name + * @return the requested description as String + */ + String getDescription(boolean includeClientInfo); + +} Index: 3rdParty_sources/spring/org/springframework/web/context/request/WebRequestInterceptor.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/web/context/request/WebRequestInterceptor.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/web/context/request/WebRequestInterceptor.java 17 Aug 2012 15:16:14 -0000 1.1 @@ -0,0 +1,89 @@ +/* + * 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.web.context.request; + +import org.springframework.ui.ModelMap; + +/** + * Interface for general web request interception. Allows for being applied + * to Servlet request as well as Portlet request environments, through + * building on the {@link WebRequest} abstraction. + * + *

This interface assumes MVC-style request processing: A handler gets executed, + * exposes a set of model objects, then a view gets rendered based on that model. + * Alternatively, a handler may also process the request completely, with no + * view to be rendered. + * + *

This interface is deliberatly minimalistic to keep the dependencies of + * generic request interceptors as minimal as feasible. + * + *

NOTE: While this interceptor is applied to the entire request processing + * in a Servlet environment, it is by default only applied to the render phase + * in a Portlet environment, preparing and rendering a Portlet view. To apply + * WebRequestInterceptors to the action phase as well, set the HandlerMapping's + * "applyWebRequestInterceptorsToRenderPhaseOnly" flag to "false". Alternatively, + * consider using the Portlet-specific HandlerInterceptor mechanism for such needs. + * + * @author Juergen Hoeller + * @since 2.0 + * @see ServletWebRequest + * @see org.springframework.web.servlet.DispatcherServlet + * @see org.springframework.web.servlet.handler.AbstractHandlerMapping#setInterceptors + * @see org.springframework.web.servlet.HandlerInterceptor + * @see org.springframework.web.portlet.context.PortletWebRequest + * @see org.springframework.web.portlet.DispatcherPortlet + * @see org.springframework.web.portlet.handler.AbstractHandlerMapping#setInterceptors + * @see org.springframework.web.portlet.handler.AbstractHandlerMapping#setApplyWebRequestInterceptorsToRenderPhaseOnly + * @see org.springframework.web.portlet.HandlerInterceptor + */ +public interface WebRequestInterceptor { + + /** + * Intercept the execution of a request handler before its invocation. + *

Allows for preparing context resources (such as a Hibernate Session) + * and expose them as request attributes or as thread-local objects. + * @param request the current web request + * @throws Exception in case of errors + */ + void preHandle(WebRequest request) throws Exception; + + /** + * Intercept the execution of a request handler after its successful + * invocation, right before view rendering (if any). + *

Allows for modifying context resources after successful handler + * execution (for example, flushing a Hibernate Session). + * @param request the current web request + * @param model the map of model objects that will be exposed to the view + * (may be null). Can be used to analyze the exposed model + * and/or to add further model attributes, if desired. + * @throws Exception in case of errors + */ + void postHandle(WebRequest request, ModelMap model) throws Exception; + + /** + * Callback after completion of request processing, that is, after rendering + * the view. Will be called on any outcome of handler execution, thus allows + * for proper resource cleanup. + *

Note: Will only be called if this interceptor's preHandle + * method has successfully completed! + * @param request the current web request + * @param ex exception thrown on handler execution, if any + * @throws Exception in case of errors + */ + void afterCompletion(WebRequest request, Exception ex) throws Exception; + +} Index: 3rdParty_sources/spring/org/springframework/web/context/request/package.html =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/web/context/request/package.html,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/web/context/request/package.html 17 Aug 2012 15:16:14 -0000 1.1 @@ -0,0 +1,8 @@ + + + +Support for generic request context holding, in particular for +scoping of application objects per HTTP request or HTTP session. + + + Index: 3rdParty_sources/spring/org/springframework/web/context/support/AbstractRefreshableWebApplicationContext.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/web/context/support/AbstractRefreshableWebApplicationContext.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/web/context/support/AbstractRefreshableWebApplicationContext.java 17 Aug 2012 15:16:05 -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.web.context.support; + +import javax.servlet.ServletConfig; +import javax.servlet.ServletContext; + +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.context.support.AbstractRefreshableConfigApplicationContext; +import org.springframework.core.io.Resource; +import org.springframework.core.io.support.ResourcePatternResolver; +import org.springframework.ui.context.Theme; +import org.springframework.ui.context.ThemeSource; +import org.springframework.ui.context.support.UiApplicationContextUtils; +import org.springframework.web.context.ConfigurableWebApplicationContext; +import org.springframework.web.context.ServletConfigAware; +import org.springframework.web.context.ServletContextAware; + +/** + * {@link org.springframework.context.support.AbstractRefreshableApplicationContext} + * subclass which implements the + * {@link org.springframework.web.context.ConfigurableWebApplicationContext} + * interface for web environments. Provides a "configLocations" property, + * to be populated through the ConfigurableWebApplicationContext interface + * on web application startup. + * + *

This class is as easy to subclass as AbstractRefreshableApplicationContext: + * All you need to implements is the {@link #loadBeanDefinitions} method; + * see the superclass javadoc for details. Note that implementations are supposed + * to load bean definitions from the files specified by the locations returned + * by the {@link #getConfigLocations} method. + * + *

Interprets resource paths as servlet context resources, i.e. as paths beneath + * the web application root. Absolute paths, e.g. for files outside the web app root, + * can be accessed via "file:" URLs, as implemented by + * {@link org.springframework.core.io.DefaultResourceLoader}. + * + *

In addition to the special beans detected by + * {@link org.springframework.context.support.AbstractApplicationContext}, + * this class detects a bean of type {@link org.springframework.ui.context.ThemeSource} + * in the context, under the special bean name "themeSource". + * + *

This is the web context to be subclassed for a different bean definition format. + * Such a context implementation can be specified as "contextClass" context-param + * for {@link org.springframework.web.context.ContextLoader} or as "contextClass" + * init-param for {@link org.springframework.web.servlet.FrameworkServlet}, + * replacing the default {@link XmlWebApplicationContext}. It will then automatically + * receive the "contextConfigLocation" context-param or init-param, respectively. + * + *

Note that WebApplicationContext implementations are generally supposed + * to configure themselves based on the configuration received through the + * {@link ConfigurableWebApplicationContext} interface. In contrast, a standalone + * application context might allow for configuration in custom startup code + * (for example, {@link org.springframework.context.support.GenericApplicationContext}). + * + * @author Juergen Hoeller + * @since 1.1.3 + * @see #loadBeanDefinitions + * @see org.springframework.web.context.ConfigurableWebApplicationContext#setConfigLocations + * @see org.springframework.ui.context.ThemeSource + * @see XmlWebApplicationContext + */ +public abstract class AbstractRefreshableWebApplicationContext extends AbstractRefreshableConfigApplicationContext + implements ConfigurableWebApplicationContext, ThemeSource { + + /** Servlet context that this context runs in */ + private ServletContext servletContext; + + /** Servlet config that this context runs in, if any */ + private ServletConfig servletConfig; + + /** Namespace of this context, or null if root */ + private String namespace; + + /** the ThemeSource for this ApplicationContext */ + private ThemeSource themeSource; + + + public AbstractRefreshableWebApplicationContext() { + setDisplayName("Root WebApplicationContext"); + } + + + public void setServletContext(ServletContext servletContext) { + this.servletContext = servletContext; + } + + public ServletContext getServletContext() { + return this.servletContext; + } + + public void setServletConfig(ServletConfig servletConfig) { + this.servletConfig = servletConfig; + if (servletConfig != null && this.servletContext == null) { + this.servletContext = servletConfig.getServletContext(); + } + } + + public ServletConfig getServletConfig() { + return this.servletConfig; + } + + public void setNamespace(String namespace) { + this.namespace = namespace; + if (namespace != null) { + setDisplayName("WebApplicationContext for namespace '" + namespace + "'"); + } + } + + public String getNamespace() { + return this.namespace; + } + + public String[] getConfigLocations() { + return super.getConfigLocations(); + } + + + /** + * Register request/session scopes, a {@link ServletContextAwareProcessor}, etc. + */ + protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) { + beanFactory.addBeanPostProcessor(new ServletContextAwareProcessor(this.servletContext, this.servletConfig)); + beanFactory.ignoreDependencyInterface(ServletContextAware.class); + beanFactory.ignoreDependencyInterface(ServletConfigAware.class); + beanFactory.registerResolvableDependency(ServletContext.class, this.servletContext); + beanFactory.registerResolvableDependency(ServletConfig.class, this.servletConfig); + + WebApplicationContextUtils.registerWebApplicationScopes(beanFactory); + } + + /** + * This implementation supports file paths beneath the root of the ServletContext. + * @see ServletContextResource + */ + protected Resource getResourceByPath(String path) { + return new ServletContextResource(this.servletContext, path); + } + + /** + * This implementation supports pattern matching in unexpanded WARs too. + * @see ServletContextResourcePatternResolver + */ + protected ResourcePatternResolver getResourcePatternResolver() { + return new ServletContextResourcePatternResolver(this); + } + + /** + * Initialize the theme capability. + */ + protected void onRefresh() { + this.themeSource = UiApplicationContextUtils.initThemeSource(this); + } + + public Theme getTheme(String themeName) { + return this.themeSource.getTheme(themeName); + } + +} Index: 3rdParty_sources/spring/org/springframework/web/context/support/ContextExposingHttpServletRequest.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/web/context/support/ContextExposingHttpServletRequest.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/web/context/support/ContextExposingHttpServletRequest.java 17 Aug 2012 15:16:06 -0000 1.1 @@ -0,0 +1,99 @@ +/* + * 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.web.context.support; + +import java.util.HashSet; +import java.util.Set; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletRequestWrapper; + +import org.springframework.util.Assert; +import org.springframework.web.context.WebApplicationContext; + +/** + * HttpServletRequest decorator that makes all Spring beans in a + * given WebApplicationContext accessible as request attributes, + * through lazy checking once an attribute gets accessed. + * + * @author Juergen Hoeller + * @since 2.5 + */ +public class ContextExposingHttpServletRequest extends HttpServletRequestWrapper { + + private final WebApplicationContext webApplicationContext; + + private final Set exposedContextBeanNames; + + private Set explicitAttributes; + + + /** + * Create a new ContextExposingHttpServletRequest for the given request. + * @param originalRequest the original HttpServletRequest + * @param context the WebApplicationContext that this request runs in + */ + public ContextExposingHttpServletRequest(HttpServletRequest originalRequest, WebApplicationContext context) { + this(originalRequest, context, null); + } + + /** + * Create a new ContextExposingHttpServletRequest for the given request. + * @param originalRequest the original HttpServletRequest + * @param context the WebApplicationContext that this request runs in + * @param exposedContextBeanNames the names of beans in the context which + * are supposed to be exposed (if this is non-null, only the beans in this + * Set are eligible for exposure as attributes) + */ + public ContextExposingHttpServletRequest( + HttpServletRequest originalRequest, WebApplicationContext context, Set exposedContextBeanNames) { + + super(originalRequest); + Assert.notNull(context, "WebApplicationContext must not be null"); + this.webApplicationContext = context; + this.exposedContextBeanNames = exposedContextBeanNames; + } + + + /** + * Return the WebApplicationContext that this request runs in. + */ + public final WebApplicationContext getWebApplicationContext() { + return this.webApplicationContext; + } + + + public Object getAttribute(String name) { + if ((this.explicitAttributes == null || !this.explicitAttributes.contains(name)) && + (this.exposedContextBeanNames == null || this.exposedContextBeanNames.contains(name)) && + this.webApplicationContext.containsBean(name)) { + return this.webApplicationContext.getBean(name); + } + else { + return super.getAttribute(name); + } + } + + public void setAttribute(String name, Object value) { + super.setAttribute(name, value); + if (this.explicitAttributes == null) { + this.explicitAttributes = new HashSet(8); + } + this.explicitAttributes.add(name); + } + +} Index: 3rdParty_sources/spring/org/springframework/web/context/support/GenericWebApplicationContext.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/web/context/support/GenericWebApplicationContext.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/web/context/support/GenericWebApplicationContext.java 17 Aug 2012 15:16:06 -0000 1.1 @@ -0,0 +1,137 @@ +/* + * 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.web.context.support; + +import javax.servlet.ServletContext; + +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.beans.factory.support.DefaultListableBeanFactory; +import org.springframework.context.support.GenericApplicationContext; +import org.springframework.core.io.Resource; +import org.springframework.core.io.support.ResourcePatternResolver; +import org.springframework.ui.context.Theme; +import org.springframework.ui.context.ThemeSource; +import org.springframework.ui.context.support.UiApplicationContextUtils; +import org.springframework.web.context.ServletContextAware; +import org.springframework.web.context.WebApplicationContext; + +/** + * Subclass of {@link GenericApplicationContext}, suitable for web environments. + * + *

Implements the {@link WebApplicationContext} interface, but not + * {@link org.springframework.web.context.ConfigurableWebApplicationContext}, + * as it is not intended for declarative setup in web.xml. Instead, + * it is designed for programmatic setup, for example for building nested contexts. + * + *

If you intend to implement a WebApplicationContext that reads bean definitions + * from configuration files, consider deriving from AbstractRefreshableWebApplicationContext, + * reading the bean definitions in an implementation of the loadBeanDefinitions + * method. + * + *

Interprets resource paths as servlet context resources, i.e. as paths beneath + * the web application root. Absolute paths, e.g. for files outside the web app root, + * can be accessed via "file:" URLs, as implemented by AbstractApplicationContext. + * + *

In addition to the special beans detected by + * {@link org.springframework.context.support.AbstractApplicationContext}, + * this class detects a ThemeSource bean in the context, with the name "themeSource". + * + * @author Juergen Hoeller + * @since 1.2 + */ +public class GenericWebApplicationContext extends GenericApplicationContext + implements WebApplicationContext, ThemeSource { + + private ServletContext servletContext; + + private ThemeSource themeSource; + + + /** + * Create a new GenericWebApplicationContext. + * @see #setServletContext + * @see #registerBeanDefinition + * @see #refresh + */ + public GenericWebApplicationContext() { + super(); + } + + /** + * Create a new GenericWebApplicationContext with the given DefaultListableBeanFactory. + * @param beanFactory the DefaultListableBeanFactory instance to use for this context + * @see #setServletContext + * @see #registerBeanDefinition + * @see #refresh + */ + public GenericWebApplicationContext(DefaultListableBeanFactory beanFactory) { + super(beanFactory); + } + + + /** + * Set the ServletContext that this WebApplicationContext runs in. + */ + public void setServletContext(ServletContext servletContext) { + this.servletContext = servletContext; + } + + public ServletContext getServletContext() { + return this.servletContext; + } + + + /** + * Register ServletContextAwareProcessor. + * @see ServletContextAwareProcessor + */ + protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) { + beanFactory.addBeanPostProcessor(new ServletContextAwareProcessor(this.servletContext)); + beanFactory.ignoreDependencyInterface(ServletContextAware.class); + beanFactory.registerResolvableDependency(ServletContext.class, this.servletContext); + + WebApplicationContextUtils.registerWebApplicationScopes(beanFactory); + } + + /** + * This implementation supports file paths beneath the root of the ServletContext. + * @see ServletContextResource + */ + protected Resource getResourceByPath(String path) { + return new ServletContextResource(this.servletContext, path); + } + + /** + * This implementation supports pattern matching in unexpanded WARs too. + * @see ServletContextResourcePatternResolver + */ + protected ResourcePatternResolver getResourcePatternResolver() { + return new ServletContextResourcePatternResolver(this); + } + + /** + * Initialize the theme capability. + */ + protected void onRefresh() { + this.themeSource = UiApplicationContextUtils.initThemeSource(this); + } + + public Theme getTheme(String themeName) { + return this.themeSource.getTheme(themeName); + } + +} Index: 3rdParty_sources/spring/org/springframework/web/context/support/HttpRequestHandlerServlet.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/web/context/support/HttpRequestHandlerServlet.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/web/context/support/HttpRequestHandlerServlet.java 17 Aug 2012 15:16:06 -0000 1.1 @@ -0,0 +1,79 @@ +/* + * 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.web.context.support; + +import java.io.IOException; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.springframework.context.i18n.LocaleContextHolder; +import org.springframework.util.StringUtils; +import org.springframework.web.HttpRequestHandler; +import org.springframework.web.HttpRequestMethodNotSupportedException; +import org.springframework.web.context.WebApplicationContext; + +/** + * Simple HttpServlet that delegates to an {@link HttpRequestHandler} bean defined + * in Spring's root web application context. The target bean name must match the + * HttpRequestHandlerServlet servlet-name as defined in web.xml. + * + *

This can for example be used to expose a single Spring remote exporter, + * such as {@link org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter} + * or {@link org.springframework.remoting.caucho.HessianServiceExporter}, + * per HttpRequestHandlerServlet definition. This is a minimal alternative + * to defining remote exporters as beans in a DispatcherServlet context + * (with advanced mapping and interception facilities being available there). + * + * @author Juergen Hoeller + * @since 2.0 + * @see org.springframework.web.HttpRequestHandler + * @see org.springframework.web.servlet.DispatcherServlet + */ +public class HttpRequestHandlerServlet extends HttpServlet { + + private HttpRequestHandler target; + + + public void init() throws ServletException { + WebApplicationContext wac = WebApplicationContextUtils.getRequiredWebApplicationContext(getServletContext()); + this.target = (HttpRequestHandler) wac.getBean(getServletName(), HttpRequestHandler.class); + } + + + protected void service(HttpServletRequest request, HttpServletResponse response) + throws ServletException, IOException { + + LocaleContextHolder.setLocale(request.getLocale()); + try { + this.target.handleRequest(request, response); + } + catch (HttpRequestMethodNotSupportedException ex) { + String[] supportedMethods = ((HttpRequestMethodNotSupportedException) ex).getSupportedMethods(); + if (supportedMethods != null) { + response.setHeader("Allow", StringUtils.arrayToDelimitedString(supportedMethods, ", ")); + } + response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, ex.getMessage()); + } + finally { + LocaleContextHolder.resetLocaleContext(); + } + } + +} Index: 3rdParty_sources/spring/org/springframework/web/context/support/PerformanceMonitorListener.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/web/context/support/PerformanceMonitorListener.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/web/context/support/PerformanceMonitorListener.java 17 Aug 2012 15:16:05 -0000 1.1 @@ -0,0 +1,57 @@ +/* + * 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.web.context.support; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import org.springframework.context.ApplicationEvent; +import org.springframework.context.ApplicationListener; +import org.springframework.util.ResponseTimeMonitorImpl; + +/** + * Listener that logs the response times of web requests. + * To be registered as bean in a WebApplicationContext. + * + *

Logs performance statistics using Commons Logging at "trace" level. + * + * @author Rod Johnson + * @author Juergen Hoeller + * @since January 21, 2001 + * @see RequestHandledEvent + * @deprecated as of Spring 2.5, to be removed in Spring 3.0. + * Use a custom ApplicationListener specific to your needs instead. + */ +public class PerformanceMonitorListener implements ApplicationListener { + + protected final Log logger = LogFactory.getLog(getClass()); + + protected final ResponseTimeMonitorImpl responseTimeMonitor = new ResponseTimeMonitorImpl(); + + + public void onApplicationEvent(ApplicationEvent event) { + if (event instanceof RequestHandledEvent) { + RequestHandledEvent rhe = (RequestHandledEvent) event; + this.responseTimeMonitor.recordResponseTime(rhe.getProcessingTimeMillis()); + if (logger.isTraceEnabled()) { + logger.trace("PerformanceMonitorListener: last=[" + rhe.getProcessingTimeMillis() + "ms]; " + + this.responseTimeMonitor + "; " + rhe.getShortDescription()); + } + } + } + +} Index: 3rdParty_sources/spring/org/springframework/web/context/support/RequestHandledEvent.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/web/context/support/RequestHandledEvent.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/web/context/support/RequestHandledEvent.java 17 Aug 2012 15:16:05 -0000 1.1 @@ -0,0 +1,157 @@ +/* + * 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.web.context.support; + +import org.springframework.context.ApplicationEvent; + +/** + * Event raised when a request is handled within an ApplicationContext. + * + *

Supported by Spring's own FrameworkServlet (through a specific + * ServletRequestHandledEvent subclass), but can also be raised by any + * other web component. Used, for example, by Spring's out-of-the-box + * PerformanceMonitorListener. + * + * @author Rod Johnson + * @author Juergen Hoeller + * @since January 17, 2001 + * @see ServletRequestHandledEvent + * @see PerformanceMonitorListener + * @see org.springframework.web.servlet.FrameworkServlet + * @see org.springframework.context.ApplicationContext#publishEvent + */ +public class RequestHandledEvent extends ApplicationEvent { + + /** Session id that applied to the request, if any */ + private String sessionId; + + /** Usually the UserPrincipal */ + private String userName; + + /** Request processing time */ + private final long processingTimeMillis; + + /** Cause of failure, if any */ + private Throwable failureCause; + + + /** + * Create a new RequestHandledEvent with session information. + * @param source the component that published the event + * @param sessionId the id of the HTTP session, if any + * @param userName the name of the user that was associated with the + * request, if any (usually the UserPrincipal) + * @param processingTimeMillis the processing time of the request in milliseconds + */ + public RequestHandledEvent(Object source, String sessionId, String userName, long processingTimeMillis) { + super(source); + this.sessionId = sessionId; + this.userName = userName; + this.processingTimeMillis = processingTimeMillis; + } + + /** + * Create a new RequestHandledEvent with session information. + * @param source the component that published the event + * @param sessionId the id of the HTTP session, if any + * @param userName the name of the user that was associated with the + * request, if any (usually the UserPrincipal) + * @param processingTimeMillis the processing time of the request in milliseconds + * @param failureCause the cause of failure, if any + */ + public RequestHandledEvent( + Object source, String sessionId, String userName, long processingTimeMillis, Throwable failureCause) { + + this(source, sessionId, userName, processingTimeMillis); + this.failureCause = failureCause; + } + + + /** + * Return the processing time of the request in milliseconds. + */ + public long getProcessingTimeMillis() { + return this.processingTimeMillis; + } + + /** + * Return the id of the HTTP session, if any. + */ + public String getSessionId() { + return this.sessionId; + } + + /** + * Return the name of the user that was associated with the request + * (usually the UserPrincipal). + * @see javax.servlet.http.HttpServletRequest#getUserPrincipal() + */ + public String getUserName() { + return this.userName; + } + + /** + * Return whether the request failed. + */ + public boolean wasFailure() { + return (this.failureCause != null); + } + + /** + * Return the cause of failure, if any. + */ + public Throwable getFailureCause() { + return this.failureCause; + } + + + /** + * Return a short description of this event, only involving + * the most important context data. + */ + public String getShortDescription() { + StringBuffer sb = new StringBuffer(); + sb.append("session=[").append(this.sessionId).append("]; "); + sb.append("user=[").append(this.userName).append("]; "); + return sb.toString(); + } + + /** + * Return a full description of this event, involving + * all available context data. + */ + public String getDescription() { + StringBuffer sb = new StringBuffer(); + sb.append("session=[").append(this.sessionId).append("]; "); + sb.append("user=[").append(this.userName).append("]; "); + sb.append("time=[").append(this.processingTimeMillis).append("ms]; "); + sb.append("status=["); + if (!wasFailure()) { + sb.append("OK"); + } + else { + sb.append("failed: ").append(this.failureCause); + } + sb.append(']'); + return sb.toString(); + } + + public String toString() { + return ("RequestHandledEvent: " + getDescription()); + } + +} Index: 3rdParty_sources/spring/org/springframework/web/context/support/ServletContextAttributeExporter.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/web/context/support/ServletContextAttributeExporter.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/web/context/support/ServletContextAttributeExporter.java 17 Aug 2012 15:16:05 -0000 1.1 @@ -0,0 +1,84 @@ +/* + * 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.web.context.support; + +import java.util.Iterator; +import java.util.Map; + +import javax.servlet.ServletContext; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import org.springframework.web.context.ServletContextAware; + +/** + * Exporter that takes Spring-defined objects and exposes them as + * ServletContext attributes. Usually, bean references will be used + * to export Spring-defined beans as ServletContext attributes. + * + *

Useful to make Spring-defined beans available to code that is + * not aware of Spring at all, but rather just of the Servlet API. + * Client code can then use plain ServletContext attribute lookups + * to access those objects, despite them being defined in a Spring + * application context. + * + *

Alternatively, consider using the WebApplicationContextUtils + * class to access Spring-defined beans via the WebApplicationContext + * interface. This makes client code aware of Spring API, of course. + * + * @author Juergen Hoeller + * @since 1.1.4 + * @see javax.servlet.ServletContext#getAttribute + * @see WebApplicationContextUtils#getWebApplicationContext + */ +public class ServletContextAttributeExporter implements ServletContextAware { + + protected final Log logger = LogFactory.getLog(getClass()); + + private Map attributes; + + /** + * Set the ServletContext attributes to expose as key-value pairs. + * Each key will be considered a ServletContext attributes key, + * and each value will be used as corresponding attribute value. + *

Usually, you will use bean references for the values, + * to export Spring-defined beans as ServletContext attributes. + * Of course, it is also possible to define plain values to export. + * @param attributes Map with String keys and Object values + */ + public void setAttributes(Map attributes) { + this.attributes = attributes; + } + + public void setServletContext(ServletContext servletContext) { + for (Iterator it = this.attributes.entrySet().iterator(); it.hasNext();) { + Map.Entry entry = (Map.Entry) it.next(); + String attributeName = (String) entry.getKey(); + if (logger.isWarnEnabled()) { + if (servletContext.getAttribute(attributeName) != null) { + logger.warn("Overwriting existing ServletContext attribute with name '" + attributeName + "'"); + } + } + servletContext.setAttribute(attributeName, entry.getValue()); + if (logger.isInfoEnabled()) { + logger.info("Exported ServletContext attribute with name '" + attributeName + "'"); + } + } + } + +} Index: 3rdParty_sources/spring/org/springframework/web/context/support/ServletContextAttributeFactoryBean.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/web/context/support/ServletContextAttributeFactoryBean.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/web/context/support/ServletContextAttributeFactoryBean.java 17 Aug 2012 15:16:05 -0000 1.1 @@ -0,0 +1,76 @@ +/* + * 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.web.context.support; + +import javax.servlet.ServletContext; + +import org.springframework.beans.factory.FactoryBean; +import org.springframework.web.context.ServletContextAware; + +/** + * FactoryBean that fetches a specific, existing ServletContext attribute. + * Exposes that ServletContext attribute when used as bean reference, + * effectively making it available as named Spring bean instance. + * + *

Intended to link in ServletContext attributes that exist before + * the startup of the Spring application context. Typically, such + * attributes will have been put there by third-party web frameworks. + * In a purely Spring-based web application, no such linking in of + * ServletContext attrutes will be necessary. + * + * @author Juergen Hoeller + * @since 1.1.4 + * @see ServletContextParameterFactoryBean + */ +public class ServletContextAttributeFactoryBean implements FactoryBean, ServletContextAware { + + private String attributeName; + + private Object attribute; + + + /** + * Set the name of the ServletContext attribute to expose. + */ + public void setAttributeName(String attributeName) { + this.attributeName = attributeName; + } + + public void setServletContext(ServletContext servletContext) { + if (this.attributeName == null) { + throw new IllegalArgumentException("attributeName is required"); + } + this.attribute = servletContext.getAttribute(this.attributeName); + if (this.attribute == null) { + throw new IllegalStateException("No ServletContext attribute '" + this.attributeName + "' found"); + } + } + + + public Object getObject() throws Exception { + return this.attribute; + } + + public Class getObjectType() { + return (this.attribute != null ? this.attribute.getClass() : null); + } + + public boolean isSingleton() { + return true; + } + +} Index: 3rdParty_sources/spring/org/springframework/web/context/support/ServletContextAwareProcessor.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/web/context/support/ServletContextAwareProcessor.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/web/context/support/ServletContextAwareProcessor.java 17 Aug 2012 15:16:05 -0000 1.1 @@ -0,0 +1,87 @@ +/* + * 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.web.context.support; + +import javax.servlet.ServletConfig; +import javax.servlet.ServletContext; + +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.config.BeanPostProcessor; +import org.springframework.web.context.ServletConfigAware; +import org.springframework.web.context.ServletContextAware; + +/** + * {@link org.springframework.beans.factory.config.BeanPostProcessor} + * implementation that passes the ServletContext to beans that implement + * the {@link ServletContextAware} interface. + * + *

Web application contexts will automatically register this with their + * underlying bean factory. Applications do not use this directly. + * + * @author Juergen Hoeller + * @since 12.03.2004 + * @see org.springframework.web.context.ServletContextAware + * @see org.springframework.web.context.support.XmlWebApplicationContext#postProcessBeanFactory + */ +public class ServletContextAwareProcessor implements BeanPostProcessor { + + private ServletContext servletContext; + + private ServletConfig servletConfig; + + + /** + * Create a new ServletContextAwareProcessor for the given context. + */ + public ServletContextAwareProcessor(ServletContext servletContext) { + this(servletContext, null); + } + + /** + * Create a new ServletContextAwareProcessor for the given config. + */ + public ServletContextAwareProcessor(ServletConfig servletConfig) { + this(null, servletConfig); + } + + /** + * Create a new ServletContextAwareProcessor for the given context and config. + */ + public ServletContextAwareProcessor(ServletContext servletContext, ServletConfig servletConfig) { + this.servletContext = servletContext; + this.servletConfig = servletConfig; + if (servletContext == null && servletConfig != null) { + this.servletContext = servletConfig.getServletContext(); + } + } + + + public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { + if (this.servletContext != null && bean instanceof ServletContextAware) { + ((ServletContextAware) bean).setServletContext(this.servletContext); + } + if (this.servletConfig != null && bean instanceof ServletConfigAware) { + ((ServletConfigAware) bean).setServletConfig(this.servletConfig); + } + return bean; + } + + public Object postProcessAfterInitialization(Object bean, String beanName) { + return bean; + } + +} Index: 3rdParty_sources/spring/org/springframework/web/context/support/ServletContextFactoryBean.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/web/context/support/ServletContextFactoryBean.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/web/context/support/ServletContextFactoryBean.java 17 Aug 2012 15:16:05 -0000 1.1 @@ -0,0 +1,65 @@ +/* + * 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.web.context.support; + +import javax.servlet.ServletContext; + +import org.springframework.beans.factory.FactoryBean; +import org.springframework.web.context.ServletContextAware; + +/** + * Simple FactoryBean that exposes the ServletContext for bean references. + * Can be used as alternative to implementing the ServletContextAware + * callback interface. Allows for passing the ServletContext reference + * to a constructor argument or any custom bean property. + * + *

Note that there's a special FactoryBean for exposing a specific + * ServletContext attribute, named ServletContextAttributeFactoryBean. + * So if all you need from the ServletContext is access to a specific + * attribute, ServletContextAttributeFactoryBean allows you to expose + * a constructor argument or bean property of the attribute type, + * which is a preferable to a dependency on the full ServletContext. + * + * @author Juergen Hoeller + * @since 1.1.4 + * @see javax.servlet.ServletContext + * @see org.springframework.web.context.ServletContextAware + * @see ServletContextAttributeFactoryBean + */ +public class ServletContextFactoryBean implements FactoryBean, ServletContextAware { + + private ServletContext servletContext; + + + public void setServletContext(ServletContext servletContext) { + this.servletContext = servletContext; + } + + + public Object getObject() { + return this.servletContext; + } + + public Class getObjectType() { + return (this.servletContext != null ? this.servletContext.getClass() : ServletContext.class); + } + + public boolean isSingleton() { + return true; + } + +} Index: 3rdParty_sources/spring/org/springframework/web/context/support/ServletContextParameterFactoryBean.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/web/context/support/ServletContextParameterFactoryBean.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/web/context/support/ServletContextParameterFactoryBean.java 17 Aug 2012 15:16:06 -0000 1.1 @@ -0,0 +1,71 @@ +/* + * 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.web.context.support; + +import javax.servlet.ServletContext; + +import org.springframework.beans.factory.FactoryBean; +import org.springframework.web.context.ServletContextAware; + +/** + * FactoryBean that retrieves a specific ServletContext init parameter + * (that is, a "context-param" defined in web.xml). + * Exposes that ServletContext init parameter when used as bean reference, + * effectively making it available as named Spring bean instance. + * + * @author Juergen Hoeller + * @since 1.2.4 + * @see ServletContextAttributeFactoryBean + */ +public class ServletContextParameterFactoryBean implements FactoryBean, ServletContextAware { + + private String initParamName; + + private String paramValue; + + + /** + * Set the name of the ServletContext init parameter to expose. + */ + public void setInitParamName(String initParamName) { + this.initParamName = initParamName; + } + + public void setServletContext(ServletContext servletContext) { + if (this.initParamName == null) { + throw new IllegalArgumentException("initParamName is required"); + } + this.paramValue = servletContext.getInitParameter(this.initParamName); + if (this.paramValue == null) { + throw new IllegalStateException("No ServletContext init parameter '" + this.initParamName + "' found"); + } + } + + + public Object getObject() throws Exception { + return this.paramValue; + } + + public Class getObjectType() { + return String.class; + } + + public boolean isSingleton() { + return true; + } + +} Index: 3rdParty_sources/spring/org/springframework/web/context/support/ServletContextPropertyPlaceholderConfigurer.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/web/context/support/ServletContextPropertyPlaceholderConfigurer.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/web/context/support/ServletContextPropertyPlaceholderConfigurer.java 17 Aug 2012 15:16:06 -0000 1.1 @@ -0,0 +1,158 @@ +/* + * 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.web.context.support; + +import java.util.Properties; + +import javax.servlet.ServletContext; + +import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer; +import org.springframework.web.context.ServletContextAware; + +/** + * Subclass of PropertyPlaceholderConfigurer that resolves placeholders as + * ServletContext init parameters (that is, web.xml context-param + * entries). + * + *

Can be combined with "locations" and/or "properties" values in addition + * to web.xml context-params. Alternatively, can be defined without local + * properties, to resolve all placeholders as web.xml context-params + * (or JVM system properties). + * + *

If a placeholder could not be resolved against the provided local + * properties within the application, this configurer will fall back to + * ServletContext parameters. Can also be configured to let ServletContext + * init parameters override local properties (contextOverride=true). + * + *

Optionally supports searching for ServletContext attributes: If turned + * on, an otherwise unresolvable placeholder will matched against the corresponding + * ServletContext attribute, using its stringified value if found. This can be + * used to feed dynamic values into Spring's placeholder resolution. + * + *

If not running within a WebApplicationContext (or any other context that + * is able to satisfy the ServletContextAware callback), this class will behave + * like the default PropertyPlaceholderConfigurer. This allows for keeping + * ServletContextPropertyPlaceholderConfigurer definitions in test suites. + * + * @author Juergen Hoeller + * @since 1.1.4 + * @see #setLocations + * @see #setProperties + * @see #setSystemPropertiesModeName + * @see #setContextOverride + * @see #setSearchContextAttributes + * @see javax.servlet.ServletContext#getInitParameter(String) + * @see javax.servlet.ServletContext#getAttribute(String) + */ +public class ServletContextPropertyPlaceholderConfigurer extends PropertyPlaceholderConfigurer + implements ServletContextAware { + + private boolean contextOverride = false; + + private boolean searchContextAttributes = false; + + private ServletContext servletContext; + + + /** + * Set whether ServletContext init parameters (and optionally also ServletContext + * attributes) should override local properties within the application. + * Default is "false": ServletContext settings serve as fallback. + *

Note that system properties will still override ServletContext settings, + * if the system properties mode is set to "SYSTEM_PROPERTIES_MODE_OVERRIDE". + * @see #setSearchContextAttributes + * @see #setSystemPropertiesModeName + * @see #SYSTEM_PROPERTIES_MODE_OVERRIDE + */ + public void setContextOverride(boolean contextOverride) { + this.contextOverride = contextOverride; + } + + /** + * Set whether to search for matching a ServletContext attribute before + * checking a ServletContext init parameter. Default is "false": only + * checking init parameters. + *

If turned on, the configurer will look for a ServletContext attribute with + * the same name as the placeholder, and use its stringified value if found. + * Exposure of such ServletContext attributes can be used to dynamically override + * init parameters defined in web.xml, for example in a custom + * context listener. + * @see javax.servlet.ServletContext#getInitParameter(String) + * @see javax.servlet.ServletContext#getAttribute(String) + */ + public void setSearchContextAttributes(boolean searchContextAttributes) { + this.searchContextAttributes = searchContextAttributes; + } + + /** + * Set the ServletContext to resolve placeholders against. + * Will be auto-populated when running in a WebApplicationContext. + *

If not set, this configurer will simply not resolve placeholders + * against the ServletContext: It will effectively behave like a plain + * PropertyPlaceholderConfigurer in such a scenario. + */ + public void setServletContext(ServletContext servletContext) { + this.servletContext = servletContext; + } + + + protected String resolvePlaceholder(String placeholder, Properties props) { + String value = null; + if (this.contextOverride && this.servletContext != null) { + value = resolvePlaceholder(placeholder, this.servletContext, this.searchContextAttributes); + } + if (value == null) { + value = super.resolvePlaceholder(placeholder, props); + } + if (value == null && this.servletContext != null) { + value = resolvePlaceholder(placeholder, this.servletContext, this.searchContextAttributes); + } + return value; + } + + /** + * Resolves the given placeholder using the init parameters + * and optionally also the attributes of the given ServletContext. + *

Default implementation checks ServletContext attributes before + * init parameters. Can be overridden to customize this behavior, + * potentially also applying specific naming patterns for parameters + * and/or attributes (instead of using the exact placeholder name). + * @param placeholder the placeholder to resolve + * @param servletContext the ServletContext to check + * @param searchContextAttributes whether to search for a matching + * ServletContext attribute + * @return the resolved value, of null if none + * @see javax.servlet.ServletContext#getInitParameter(String) + * @see javax.servlet.ServletContext#getAttribute(String) + */ + protected String resolvePlaceholder( + String placeholder, ServletContext servletContext, boolean searchContextAttributes) { + + String value = null; + if (searchContextAttributes) { + Object attrValue = servletContext.getAttribute(placeholder); + if (attrValue != null) { + value = attrValue.toString(); + } + } + if (value == null) { + value = servletContext.getInitParameter(placeholder); + } + return value; + } + +} Index: 3rdParty_sources/spring/org/springframework/web/context/support/ServletContextResource.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/web/context/support/ServletContextResource.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/web/context/support/ServletContextResource.java 17 Aug 2012 15:16:06 -0000 1.1 @@ -0,0 +1,200 @@ +/* + * 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.web.context.support; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.net.MalformedURLException; +import java.net.URL; + +import javax.servlet.ServletContext; + +import org.springframework.core.io.AbstractResource; +import org.springframework.core.io.ContextResource; +import org.springframework.core.io.Resource; +import org.springframework.util.Assert; +import org.springframework.util.StringUtils; +import org.springframework.web.util.WebUtils; + +/** + * {@link org.springframework.core.io.Resource} implementation for + * {@link javax.servlet.ServletContext} resources, interpreting + * relative paths within the web application root directory. + * + *

Always supports stream access and URL access, but only allows + * java.io.File access when the web application archive + * is expanded. + * + * @author Juergen Hoeller + * @since 28.12.2003 + * @see javax.servlet.ServletContext#getResourceAsStream + * @see javax.servlet.ServletContext#getResource + * @see javax.servlet.ServletContext#getRealPath + */ +public class ServletContextResource extends AbstractResource implements ContextResource { + + private final ServletContext servletContext; + + private final String path; + + + /** + * Create a new ServletContextResource. + *

The Servlet spec requires that resource paths start with a slash, + * even if many containers accept paths without leading slash too. + * Consequently, the given path will be prepended with a slash if it + * doesn't already start with one. + * @param servletContext the ServletContext to load from + * @param path the path of the resource + */ + public ServletContextResource(ServletContext servletContext, String path) { + // check ServletContext + Assert.notNull(servletContext, "Cannot resolve ServletContextResource without ServletContext"); + this.servletContext = servletContext; + + // check path + Assert.notNull(path, "Path is required"); + String pathToUse = StringUtils.cleanPath(path); + if (!pathToUse.startsWith("/")) { + pathToUse = "/" + pathToUse; + } + this.path = pathToUse; + } + + /** + * Return the ServletContext for this resource. + */ + public final ServletContext getServletContext() { + return this.servletContext; + } + + /** + * Return the path for this resource. + */ + public final String getPath() { + return this.path; + } + + + /** + * This implementation checks ServletContext.getResource. + * @see javax.servlet.ServletContext#getResource(String) + */ + public boolean exists() { + try { + URL url = this.servletContext.getResource(this.path); + return (url != null); + } + catch (MalformedURLException ex) { + return false; + } + } + + /** + * This implementation delegates to ServletContext.getResourceAsStream, + * but throws a FileNotFoundException if no resource found. + * @see javax.servlet.ServletContext#getResourceAsStream(String) + */ + public InputStream getInputStream() throws IOException { + InputStream is = this.servletContext.getResourceAsStream(this.path); + if (is == null) { + throw new FileNotFoundException("Could not open " + getDescription()); + } + return is; + } + + /** + * This implementation delegates to ServletContext.getResource, + * but throws a FileNotFoundException if no resource found. + * @see javax.servlet.ServletContext#getResource(String) + */ + public URL getURL() throws IOException { + URL url = this.servletContext.getResource(this.path); + if (url == null) { + throw new FileNotFoundException( + getDescription() + " cannot be resolved to URL because it does not exist"); + } + return url; + } + + /** + * This implementation delegates to ServletContext.getRealPath, + * but throws a FileNotFoundException if not found or not resolvable. + * @see javax.servlet.ServletContext#getRealPath(String) + */ + public File getFile() throws IOException { + String realPath = WebUtils.getRealPath(this.servletContext, this.path); + return new File(realPath); + } + + /** + * This implementation creates a ServletContextResource, applying the given path + * relative to the path of the underlying file of this resource descriptor. + * @see org.springframework.util.StringUtils#applyRelativePath(String, String) + */ + public Resource createRelative(String relativePath) { + String pathToUse = StringUtils.applyRelativePath(this.path, relativePath); + return new ServletContextResource(this.servletContext, pathToUse); + } + + /** + * This implementation returns the name of the file that this ServletContext + * resource refers to. + * @see org.springframework.util.StringUtils#getFilename(String) + */ + public String getFilename() { + return StringUtils.getFilename(this.path); + } + + /** + * This implementation returns a description that includes the ServletContext + * resource location. + */ + public String getDescription() { + return "ServletContext resource [" + this.path + "]"; + } + + public String getPathWithinContext() { + return this.path; + } + + + /** + * This implementation compares the underlying ServletContext resource locations. + */ + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + if (obj instanceof ServletContextResource) { + ServletContextResource otherRes = (ServletContextResource) obj; + return (this.servletContext.equals(otherRes.servletContext) && this.path.equals(otherRes.path)); + } + return false; + } + + /** + * This implementation returns the hash code of the underlying + * ServletContext resource location. + */ + public int hashCode() { + return this.path.hashCode(); + } + +} Index: 3rdParty_sources/spring/org/springframework/web/context/support/ServletContextResourceLoader.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/web/context/support/ServletContextResourceLoader.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/web/context/support/ServletContextResourceLoader.java 17 Aug 2012 15:16:06 -0000 1.1 @@ -0,0 +1,61 @@ +/* + * 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.web.context.support; + +import javax.servlet.ServletContext; + +import org.springframework.core.io.DefaultResourceLoader; +import org.springframework.core.io.Resource; + +/** + * ResourceLoader implementation that resolves paths as ServletContext + * resources, for use outside a WebApplicationContext (for example, + * in a HttpServletBean or GenericFilterBean subclass). + * + *

Within a WebApplicationContext, resource paths are automatically + * resolved as ServletContext resources by the context implementation. + * + * @author Juergen Hoeller + * @since 1.0.2 + * @see #getResourceByPath + * @see ServletContextResource + * @see org.springframework.web.context.WebApplicationContext + * @see org.springframework.web.servlet.HttpServletBean + * @see org.springframework.web.filter.GenericFilterBean + */ +public class ServletContextResourceLoader extends DefaultResourceLoader { + + private final ServletContext servletContext; + + + /** + * Create a new ServletContextResourceLoader. + * @param servletContext the ServletContext to load resources with + */ + public ServletContextResourceLoader(ServletContext servletContext) { + this.servletContext = servletContext; + } + + /** + * This implementation supports file paths beneath the root of the web application. + * @see ServletContextResource + */ + protected Resource getResourceByPath(String path) { + return new ServletContextResource(this.servletContext, path); + } + +} Index: 3rdParty_sources/spring/org/springframework/web/context/support/ServletContextResourcePatternResolver.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/web/context/support/ServletContextResourcePatternResolver.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/web/context/support/ServletContextResourcePatternResolver.java 17 Aug 2012 15:16:05 -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.web.context.support; + +import java.io.IOException; +import java.util.Iterator; +import java.util.LinkedHashSet; +import java.util.Set; + +import javax.servlet.ServletContext; + +import org.springframework.core.io.Resource; +import org.springframework.core.io.ResourceLoader; +import org.springframework.core.io.support.PathMatchingResourcePatternResolver; +import org.springframework.util.StringUtils; + +/** + * ServletContext-aware subclass of {@link PathMatchingResourcePatternResolver}, + * able to find matching resources below the web application root directory + * via Servlet 2.3's ServletContext.getResourcePaths. + * Falls back to the superclass' file system checking for other resources. + * + * @author Juergen Hoeller + * @since 1.1.2 + */ +public class ServletContextResourcePatternResolver extends PathMatchingResourcePatternResolver { + + /** + * Create a new ServletContextResourcePatternResolver. + * @param servletContext the ServletContext to load resources with + * @see ServletContextResourceLoader#ServletContextResourceLoader(javax.servlet.ServletContext) + */ + public ServletContextResourcePatternResolver(ServletContext servletContext) { + super(new ServletContextResourceLoader(servletContext)); + } + + /** + * Create a new ServletContextResourcePatternResolver. + * @param resourceLoader the ResourceLoader to load root directories and + * actual resources with + */ + public ServletContextResourcePatternResolver(ResourceLoader resourceLoader) { + super(resourceLoader); + } + + + /** + * Overridden version which checks for ServletContextResource + * and uses ServletContext.getResourcePaths to find + * matching resources below the web application root directory. + * In case of other resources, delegates to the superclass version. + * @see #doRetrieveMatchingServletContextResources + * @see ServletContextResource + * @see javax.servlet.ServletContext#getResourcePaths + */ + protected Set doFindPathMatchingFileResources(Resource rootDirResource, String subPattern) throws IOException { + if (rootDirResource instanceof ServletContextResource) { + ServletContextResource scResource = (ServletContextResource) rootDirResource; + ServletContext sc = scResource.getServletContext(); + String fullPattern = scResource.getPath() + subPattern; + Set result = new LinkedHashSet(8); + doRetrieveMatchingServletContextResources(sc, fullPattern, scResource.getPath(), result); + return result; + } + else { + return super.doFindPathMatchingFileResources(rootDirResource, subPattern); + } + } + + /** + * Recursively retrieve ServletContextResources that match the given pattern, + * adding them to the given result set. + * @param servletContext the ServletContext to work on + * @param fullPattern the pattern to match against, + * with preprended root directory path + * @param dir the current directory + * @param result the Set of matching Resources to add to + * @throws IOException if directory contents could not be retrieved + * @see ServletContextResource + * @see javax.servlet.ServletContext#getResourcePaths + */ + protected void doRetrieveMatchingServletContextResources( + ServletContext servletContext, String fullPattern, String dir, Set result) throws IOException { + + Set candidates = servletContext.getResourcePaths(dir); + if (candidates != null) { + boolean dirDepthNotFixed = (fullPattern.indexOf("**") != -1); + for (Iterator it = candidates.iterator(); it.hasNext();) { + String currPath = (String) it.next(); + if (!currPath.startsWith(dir)) { + // Returned resource path does not start with relative directory: + // assuming absolute path returned -> strip absolute path. + int dirIndex = currPath.indexOf(dir); + if (dirIndex != -1) { + currPath = currPath.substring(dirIndex); + } + } + if (currPath.endsWith("/") && + (dirDepthNotFixed || + StringUtils.countOccurrencesOf(currPath, "/") <= StringUtils.countOccurrencesOf(fullPattern, "/"))) { + // Search subdirectories recursively: ServletContext.getResourcePaths + // only returns entries for one directory level. + doRetrieveMatchingServletContextResources(servletContext, fullPattern, currPath, result); + } + if (getPathMatcher().match(fullPattern, currPath)) { + result.add(new ServletContextResource(servletContext, currPath)); + } + } + } + } + +} Index: 3rdParty_sources/spring/org/springframework/web/context/support/ServletRequestHandledEvent.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/web/context/support/ServletRequestHandledEvent.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/web/context/support/ServletRequestHandledEvent.java 17 Aug 2012 15:16:06 -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.web.context.support; + +/** + * Servlet-specific subclass of RequestHandledEvent, + * adding servlet-specific context information. + * + * @author Juergen Hoeller + * @since 2.0 + * @see org.springframework.web.servlet.FrameworkServlet + * @see org.springframework.context.ApplicationContext#publishEvent + */ +public class ServletRequestHandledEvent extends RequestHandledEvent { + + /** URL that the triggered the request */ + private final String requestUrl; + + /** IP address that the request came from */ + private final String clientAddress; + + /** Usually GET or POST */ + private final String method; + + /** Name of the servlet that handled the request */ + private final String servletName; + + + /** + * Create a new ServletRequestHandledEvent. + * @param source the component that published the event + * @param requestUrl the URL of the request + * @param clientAddress the IP address that the request came from + * @param method the HTTP method of the request (usually GET or POST) + * @param servletName the name of the servlet that handled the request + * @param sessionId the id of the HTTP session, if any + * @param userName the name of the user that was associated with the + * request, if any (usually the UserPrincipal) + * @param processingTimeMillis the processing time of the request in milliseconds + */ + public ServletRequestHandledEvent(Object source, String requestUrl, + String clientAddress, String method, String servletName, + String sessionId, String userName, long processingTimeMillis) { + + super(source, sessionId, userName, processingTimeMillis); + this.requestUrl = requestUrl; + this.clientAddress = clientAddress; + this.method = method; + this.servletName = servletName; + } + + /** + * Create a new ServletRequestHandledEvent. + * @param source the component that published the event + * @param requestUrl the URL of the request + * @param clientAddress the IP address that the request came from + * @param method the HTTP method of the request (usually GET or POST) + * @param servletName the name of the servlet that handled the request + * @param sessionId the id of the HTTP session, if any + * @param userName the name of the user that was associated with the + * request, if any (usually the UserPrincipal) + * @param processingTimeMillis the processing time of the request in milliseconds + * @param failureCause the cause of failure, if any + */ + public ServletRequestHandledEvent(Object source, String requestUrl, + String clientAddress, String method, String servletName, String sessionId, + String userName, long processingTimeMillis, Throwable failureCause) { + + super(source, sessionId, userName, processingTimeMillis, failureCause); + this.requestUrl = requestUrl; + this.clientAddress = clientAddress; + this.method = method; + this.servletName = servletName; + } + + + /** + * Return the URL of the request. + */ + public String getRequestUrl() { + return this.requestUrl; + } + + /** + * Return the IP address that the request came from. + */ + public String getClientAddress() { + return this.clientAddress; + } + + /** + * Return the HTTP method of the request (usually GET or POST). + */ + public String getMethod() { + return this.method; + } + + /** + * Return the name of the servlet that handled the request. + */ + public String getServletName() { + return this.servletName; + } + + + public String getShortDescription() { + StringBuffer sb = new StringBuffer(); + sb.append("url=[").append(getRequestUrl()).append("]; "); + sb.append("client=[").append(getClientAddress()).append("]; "); + sb.append(super.getShortDescription()); + return sb.toString(); + } + + public String getDescription() { + StringBuffer sb = new StringBuffer(); + sb.append("url=[").append(getRequestUrl()).append("]; "); + sb.append("client=[").append(getClientAddress()).append("]; "); + sb.append("method=[").append(getMethod()).append("]; "); + sb.append("servlet=[").append(getServletName()).append("]; "); + sb.append(super.getDescription()); + return sb.toString(); + } + + public String toString() { + return "ServletRequestHandledEvent: " + getDescription(); + } + +} Index: 3rdParty_sources/spring/org/springframework/web/context/support/SpringBeanAutowiringSupport.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/web/context/support/SpringBeanAutowiringSupport.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/web/context/support/SpringBeanAutowiringSupport.java 17 Aug 2012 15:16:05 -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.web.context.support; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor; +import org.springframework.util.Assert; +import org.springframework.util.ClassUtils; +import org.springframework.web.context.ContextLoader; +import org.springframework.web.context.WebApplicationContext; + +/** + * Convenient base class for self-autowiring classes that gets constructed + * within a Spring-based web application. Resolves @Autowired + * annotations in the endpoint class against beans in the current Spring + * root web application context (as determined by the current thread's + * context ClassLoader, which needs to be the web application's ClassLoader). + * Can alternatively be used as a delegate instead of as a base class. + * + *

A typical usage of this base class is a JAX-WS endpoint class: + * Such a Spring-based JAX-WS endpoint implementation will follow the + * standard JAX-WS contract for endpoint classes but will be 'thin' + * in that it delegates the actual work to one or more Spring-managed + * service beans - typically obtained using @Autowired. + * The lifecycle of such an endpoint instance will be managed by the + * JAX-WS runtime, hence the need for this base class to provide + * @Autowired processing based on the current Spring context. + * + *

NOTE: If there is an explicit way to access the ServletContext, + * prefer such a way over using this class. The {@link WebApplicationContextUtils} + * class allows for easy access to the Spring root web application context + * based on the ServletContext. + * + * @author Juergen Hoeller + * @since 2.5.1 + * @see WebApplicationObjectSupport + */ +public abstract class SpringBeanAutowiringSupport { + + private static final Log logger = LogFactory.getLog(SpringBeanAutowiringSupport.class); + + + /** + * This constructor performs injection on this instance, + * based on the current web application context. + *

Intended for use as a base class. + * @see #processInjectionBasedOnCurrentContext + */ + public SpringBeanAutowiringSupport() { + processInjectionBasedOnCurrentContext(this); + } + + + /** + * Process @Autowired injection for the given target object, + * based on the current web application context. + *

Intended for use as a delegate. + * @param target the target object to process + * @see org.springframework.web.context.ContextLoader#getCurrentWebApplicationContext() + */ + public static void processInjectionBasedOnCurrentContext(Object target) { + Assert.notNull(target, "Target object must not be null"); + WebApplicationContext cc = ContextLoader.getCurrentWebApplicationContext(); + if (cc != null) { + AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor(); + bpp.setBeanFactory(cc.getAutowireCapableBeanFactory()); + bpp.processInjection(target); + } + else { + if (logger.isDebugEnabled()) { + logger.debug("Current WebApplicationContext is not available for processing of " + + ClassUtils.getShortName(target.getClass()) + ": " + + "Make sure this class gets constructed in a Spring web application. Proceeding without injection."); + } + } + } + +} Index: 3rdParty_sources/spring/org/springframework/web/context/support/StaticWebApplicationContext.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/web/context/support/StaticWebApplicationContext.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/web/context/support/StaticWebApplicationContext.java 17 Aug 2012 15:16:05 -0000 1.1 @@ -0,0 +1,172 @@ +/* + * 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.web.context.support; + +import javax.servlet.ServletConfig; +import javax.servlet.ServletContext; + +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.context.support.StaticApplicationContext; +import org.springframework.core.io.Resource; +import org.springframework.core.io.support.ResourcePatternResolver; +import org.springframework.ui.context.Theme; +import org.springframework.ui.context.ThemeSource; +import org.springframework.ui.context.support.UiApplicationContextUtils; +import org.springframework.web.context.ConfigurableWebApplicationContext; +import org.springframework.web.context.ServletConfigAware; +import org.springframework.web.context.ServletContextAware; +import org.springframework.web.context.request.RequestScope; +import org.springframework.web.context.request.SessionScope; + +/** + * Static {@link org.springframework.web.context.WebApplicationContext} + * implementation for testing. Not intended for use in production applications. + * + *

Implements the {@link org.springframework.web.context.ConfigurableWebApplicationContext} + * interface to allow for direct replacement of an {@link XmlWebApplicationContext}, + * despite not actually supporting external configuration files. + * + *

Interprets resource paths as servlet context resources, i.e. as paths beneath + * the web application root. Absolute paths, e.g. for files outside the web app root, + * can be accessed via "file:" URLs, as implemented by + * {@link org.springframework.core.io.DefaultResourceLoader}. + * + *

In addition to the special beans detected by + * {@link org.springframework.context.support.AbstractApplicationContext}, + * this class detects a bean of type {@link org.springframework.ui.context.ThemeSource} + * in the context, under the special bean name "themeSource". + * + * @author Rod Johnson + * @author Juergen Hoeller + * @see org.springframework.ui.context.ThemeSource + */ +public class StaticWebApplicationContext extends StaticApplicationContext + implements ConfigurableWebApplicationContext, ThemeSource { + + private ServletContext servletContext; + + private ServletConfig servletConfig; + + private String namespace; + + private ThemeSource themeSource; + + + public StaticWebApplicationContext() { + setDisplayName("Root WebApplicationContext"); + } + + + /** + * Set the ServletContext that this WebApplicationContext runs in. + */ + public void setServletContext(ServletContext servletContext) { + this.servletContext = servletContext; + } + + public ServletContext getServletContext() { + return this.servletContext; + } + + public void setServletConfig(ServletConfig servletConfig) { + this.servletConfig = servletConfig; + if (servletConfig != null && this.servletContext == null) { + this.servletContext = servletConfig.getServletContext(); + } + } + + public ServletConfig getServletConfig() { + return this.servletConfig; + } + + public void setNamespace(String namespace) { + this.namespace = namespace; + if (namespace != null) { + setDisplayName("WebApplicationContext for namespace '" + namespace + "'"); + } + } + + public String getNamespace() { + return this.namespace; + } + + /** + * The {@link StaticWebApplicationContext} class does not support this method. + * @throws UnsupportedOperationException always + */ + public void setConfigLocation(String configLocation) { + if (configLocation != null) { + throw new UnsupportedOperationException("StaticWebApplicationContext does not support config locations"); + } + } + + /** + * The {@link StaticWebApplicationContext} class does not support this method. + * @throws UnsupportedOperationException always + */ + public void setConfigLocations(String[] configLocations) { + if (configLocations != null) { + throw new UnsupportedOperationException("StaticWebApplicationContext does not support config locations"); + } + } + + public String[] getConfigLocations() { + return null; + } + + + /** + * Register request/session scopes, a {@link ServletContextAwareProcessor}, etc. + */ + protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) { + beanFactory.registerScope(SCOPE_REQUEST, new RequestScope()); + beanFactory.registerScope(SCOPE_SESSION, new SessionScope(false)); + beanFactory.registerScope(SCOPE_GLOBAL_SESSION, new SessionScope(true)); + + beanFactory.addBeanPostProcessor(new ServletContextAwareProcessor(this.servletContext, this.servletConfig)); + beanFactory.ignoreDependencyInterface(ServletContextAware.class); + beanFactory.ignoreDependencyInterface(ServletConfigAware.class); + } + + /** + * This implementation supports file paths beneath the root of the ServletContext. + * @see ServletContextResource + */ + protected Resource getResourceByPath(String path) { + return new ServletContextResource(this.servletContext, path); + } + + /** + * This implementation supports pattern matching in unexpanded WARs too. + * @see ServletContextResourcePatternResolver + */ + protected ResourcePatternResolver getResourcePatternResolver() { + return new ServletContextResourcePatternResolver(this); + } + + /** + * Initialize the theme capability. + */ + protected void onRefresh() { + this.themeSource = UiApplicationContextUtils.initThemeSource(this); + } + + public Theme getTheme(String themeName) { + return this.themeSource.getTheme(themeName); + } + +} Index: 3rdParty_sources/spring/org/springframework/web/context/support/WebApplicationContextUtils.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/web/context/support/WebApplicationContextUtils.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/web/context/support/WebApplicationContextUtils.java 17 Aug 2012 15:16:05 -0000 1.1 @@ -0,0 +1,149 @@ +/* + * 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.web.context.support; + +import javax.servlet.ServletContext; +import javax.servlet.ServletRequest; +import javax.servlet.http.HttpSession; + +import org.springframework.beans.factory.ObjectFactory; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.util.Assert; +import org.springframework.web.context.WebApplicationContext; +import org.springframework.web.context.request.RequestAttributes; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.RequestScope; +import org.springframework.web.context.request.ServletRequestAttributes; +import org.springframework.web.context.request.SessionScope; + +/** + * Convenience methods for retrieving the root + * {@link org.springframework.web.context.WebApplicationContext} for a given + * ServletContext. This is e.g. useful for accessing a Spring + * context from within custom web views or Struts actions. + * + *

Note that there are more convenient ways of accessing the root context for + * many web frameworks, either part of Spring or available as external library. + * This helper class is just the most generic way to access the root context. + * + * @author Juergen Hoeller + * @see org.springframework.web.context.ContextLoader + * @see org.springframework.web.servlet.FrameworkServlet + * @see org.springframework.web.servlet.DispatcherServlet + * @see org.springframework.web.struts.ActionSupport + * @see org.springframework.web.struts.DelegatingActionProxy + * @see org.springframework.web.jsf.FacesContextUtils + * @see org.springframework.web.jsf.DelegatingVariableResolver + */ +public abstract class WebApplicationContextUtils { + + /** + * Find the root WebApplicationContext for this web application, which is + * typically loaded via {@link org.springframework.web.context.ContextLoaderListener} or + * {@link org.springframework.web.context.ContextLoaderServlet}. + *

Will rethrow an exception that happened on root context startup, + * to differentiate between a failed context startup and no context at all. + * @param sc ServletContext to find the web application context for + * @return the root WebApplicationContext for this web app + * @throws IllegalStateException if the root WebApplicationContext could not be found + * @see org.springframework.web.context.WebApplicationContext#ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE + */ + public static WebApplicationContext getRequiredWebApplicationContext(ServletContext sc) + throws IllegalStateException { + + WebApplicationContext wac = getWebApplicationContext(sc); + if (wac == null) { + throw new IllegalStateException("No WebApplicationContext found: no ContextLoaderListener registered?"); + } + return wac; + } + + /** + * Find the root WebApplicationContext for this web application, which is + * typically loaded via {@link org.springframework.web.context.ContextLoaderListener} or + * {@link org.springframework.web.context.ContextLoaderServlet}. + *

Will rethrow an exception that happened on root context startup, + * to differentiate between a failed context startup and no context at all. + * @param sc ServletContext to find the web application context for + * @return the root WebApplicationContext for this web app, or null if none + * @see org.springframework.web.context.WebApplicationContext#ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE + */ + public static WebApplicationContext getWebApplicationContext(ServletContext sc) { + return getWebApplicationContext(sc, WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE); + } + + /** + * Find a custom WebApplicationContext for this web application. + * @param sc ServletContext to find the web application context for + * @param attrName the name of the ServletContext attribute to look for + * @return the desired WebApplicationContext for this web app, or null if none + */ + public static WebApplicationContext getWebApplicationContext(ServletContext sc, String attrName) { + Assert.notNull(sc, "ServletContext must not be null"); + Object attr = sc.getAttribute(attrName); + if (attr == null) { + return null; + } + if (attr instanceof RuntimeException) { + throw (RuntimeException) attr; + } + if (attr instanceof Error) { + throw (Error) attr; + } + if (attr instanceof Exception) { + IllegalStateException ex = new IllegalStateException(); + ex.initCause((Exception) attr); + throw ex; + } + if (!(attr instanceof WebApplicationContext)) { + throw new IllegalStateException("Context attribute is not of type WebApplicationContext: " + attr); + } + return (WebApplicationContext) attr; + } + + + /** + * Register web-specific scopes with the given BeanFactory, + * as used by the WebApplicationContext. + * @param beanFactory the BeanFactory to configure + */ + public static void registerWebApplicationScopes(ConfigurableListableBeanFactory beanFactory) { + beanFactory.registerScope(WebApplicationContext.SCOPE_REQUEST, new RequestScope()); + beanFactory.registerScope(WebApplicationContext.SCOPE_SESSION, new SessionScope(false)); + beanFactory.registerScope(WebApplicationContext.SCOPE_GLOBAL_SESSION, new SessionScope(true)); + + beanFactory.registerResolvableDependency(ServletRequest.class, new ObjectFactory() { + public Object getObject() { + RequestAttributes requestAttr = RequestContextHolder.currentRequestAttributes(); + if (!(requestAttr instanceof ServletRequestAttributes)) { + throw new IllegalStateException("Current request is not a servlet request"); + } + return ((ServletRequestAttributes) requestAttr).getRequest(); + } + }); + beanFactory.registerResolvableDependency(HttpSession.class, new ObjectFactory() { + public Object getObject() { + RequestAttributes requestAttr = RequestContextHolder.currentRequestAttributes(); + if (!(requestAttr instanceof ServletRequestAttributes)) { + throw new IllegalStateException("Current request is not a servlet request"); + } + return ((ServletRequestAttributes) requestAttr).getRequest().getSession(); + } + }); + } + +} Index: 3rdParty_sources/spring/org/springframework/web/context/support/WebApplicationObjectSupport.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/web/context/support/WebApplicationObjectSupport.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/web/context/support/WebApplicationObjectSupport.java 17 Aug 2012 15:16:05 -0000 1.1 @@ -0,0 +1,140 @@ +/* + * 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.web.context.support; + +import java.io.File; + +import javax.servlet.ServletContext; + +import org.springframework.context.ApplicationContext; +import org.springframework.context.support.ApplicationObjectSupport; +import org.springframework.web.context.ServletContextAware; +import org.springframework.web.context.WebApplicationContext; +import org.springframework.web.util.WebUtils; + +/** + * Convenient superclass for application objects running in a WebApplicationContext. + * Provides getWebApplicationContext(), getServletContext(), + * and getTempDir() methods. + * + * @author Juergen Hoeller + * @since 28.08.2003 + * @see SpringBeanAutowiringSupport + */ +public abstract class WebApplicationObjectSupport extends ApplicationObjectSupport + implements ServletContextAware { + + private ServletContext servletContext; + + + public final void setServletContext(ServletContext servletContext) { + this.servletContext = servletContext; + if (servletContext != null) { + initServletContext(servletContext); + } + } + + /** + * Overrides the base class behavior to enforce running in an ApplicationContext. + * All accessors will throw IllegalStateException if not running in a context. + * @see #getApplicationContext() + * @see #getMessageSourceAccessor() + * @see #getWebApplicationContext() + * @see #getServletContext() + * @see #getTempDir() + */ + protected boolean isContextRequired() { + return true; + } + + /** + * Calls {@link #initServletContext(javax.servlet.ServletContext)} if the + * given ApplicationContext is a {@link WebApplicationContext}. + */ + protected void initApplicationContext(ApplicationContext context) { + super.initApplicationContext(context); + if (context instanceof WebApplicationContext) { + ServletContext servletContext = ((WebApplicationContext) context).getServletContext(); + if (servletContext != null) { + initServletContext(servletContext); + } + } + } + + /** + * Subclasses may override this for custom initialization based + * on the ServletContext that this application object runs in. + *

The default implementation is empty. Called by + * {@link #initApplicationContext(org.springframework.context.ApplicationContext)} + * as well as {@link #setServletContext(javax.servlet.ServletContext)}. + * @param servletContext the ServletContext that this application object runs in + * (never null) + */ + protected void initServletContext(ServletContext servletContext) { + } + + /** + * Return the current application context as WebApplicationContext. + *

NOTE: Only use this if you actually need to access + * WebApplicationContext-specific functionality. Preferably use + * getApplicationContext() or getServletContext() + * else, to be able to run in non-WebApplicationContext environments as well. + * @throws IllegalStateException if not running in a WebApplicationContext + * @see #getApplicationContext() + */ + protected final WebApplicationContext getWebApplicationContext() throws IllegalStateException { + ApplicationContext ctx = getApplicationContext(); + if (ctx instanceof WebApplicationContext) { + return (WebApplicationContext) getApplicationContext(); + } + else if (isContextRequired()) { + throw new IllegalStateException("WebApplicationObjectSupport instance [" + this + + "] does not run in a WebApplicationContext but in: " + ctx); + } + else { + return null; + } + } + + /** + * Return the current ServletContext. + * @throws IllegalStateException if not running within a ServletContext + */ + protected final ServletContext getServletContext() throws IllegalStateException { + if (this.servletContext != null) { + return this.servletContext; + } + ServletContext servletContext = getWebApplicationContext().getServletContext(); + if (servletContext == null && isContextRequired()) { + throw new IllegalStateException("WebApplicationObjectSupport instance [" + this + + "] does not run within a ServletContext. Make sure the object is fully configured!"); + } + return servletContext; + } + + /** + * Return the temporary directory for the current web application, + * as provided by the servlet container. + * @return the File representing the temporary directory + * @throws IllegalStateException if not running within a ServletContext + * @see org.springframework.web.util.WebUtils#getTempDir(javax.servlet.ServletContext) + */ + protected final File getTempDir() throws IllegalStateException { + return WebUtils.getTempDir(getServletContext()); + } + +} Index: 3rdParty_sources/spring/org/springframework/web/context/support/XmlWebApplicationContext.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/web/context/support/XmlWebApplicationContext.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/web/context/support/XmlWebApplicationContext.java 17 Aug 2012 15:16:06 -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.web.context.support; + +import java.io.IOException; + +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.support.DefaultListableBeanFactory; +import org.springframework.beans.factory.xml.ResourceEntityResolver; +import org.springframework.beans.factory.xml.XmlBeanDefinitionReader; + +/** + * {@link org.springframework.web.context.WebApplicationContext} implementation + * which takes its configuration from XML documents, understood by an + * {@link org.springframework.beans.factory.xml.XmlBeanDefinitionReader}. + * This is essentially the equivalent of + * {@link org.springframework.context.support.AbstractXmlApplicationContext} + * for a web environment. + * + *

By default, the configuration will be taken from "/WEB-INF/applicationContext.xml" + * for the root context, and "/WEB-INF/test-servlet.xml" for a context with the namespace + * "test-servlet" (like for a DispatcherServlet instance with the servlet-name "test"). + * + *

The config location defaults can be overridden via the "contextConfigLocation" + * context-param of {@link org.springframework.web.context.ContextLoader} and servlet + * init-param of {@link org.springframework.web.servlet.FrameworkServlet}. Config locations + * can either denote concrete files like "/WEB-INF/context.xml" or Ant-style patterns + * like "/WEB-INF/*-context.xml" (see {@link org.springframework.util.PathMatcher} + * javadoc for pattern details). + * + *

Note: In case of multiple config locations, later bean definitions will + * override ones defined in earlier loaded files. This can be leveraged to + * deliberately override certain bean definitions via an extra XML file. + * + *

For a WebApplicationContext that reads in a different bean definition format, + * create an analogous subclass of {@link AbstractRefreshableWebApplicationContext}. + * Such a context implementation can be specified as "contextClass" context-param + * for ContextLoader or "contextClass" init-param for FrameworkServlet. + * + * @author Rod Johnson + * @author Juergen Hoeller + * @see #setNamespace + * @see #setConfigLocations + * @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader + * @see org.springframework.web.context.ContextLoader#initWebApplicationContext + * @see org.springframework.web.servlet.FrameworkServlet#initWebApplicationContext + */ +public class XmlWebApplicationContext extends AbstractRefreshableWebApplicationContext { + + /** Default config location for the root context */ + public static final String DEFAULT_CONFIG_LOCATION = "/WEB-INF/applicationContext.xml"; + + /** Default prefix for building a config location for a namespace */ + public static final String DEFAULT_CONFIG_LOCATION_PREFIX = "/WEB-INF/"; + + /** Default suffix for building a config location for a namespace */ + public static final String DEFAULT_CONFIG_LOCATION_SUFFIX = ".xml"; + + + /** + * Loads the bean definitions via an XmlBeanDefinitionReader. + * @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader + * @see #initBeanDefinitionReader + * @see #loadBeanDefinitions + */ + protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws IOException { + // Create a new XmlBeanDefinitionReader for the given BeanFactory. + XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory); + + // Configure the bean definition reader with this context's + // resource loading environment. + beanDefinitionReader.setResourceLoader(this); + beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this)); + + // Allow a subclass to provide custom initialization of the reader, + // then proceed with actually loading the bean definitions. + initBeanDefinitionReader(beanDefinitionReader); + loadBeanDefinitions(beanDefinitionReader); + } + + /** + * Initialize the bean definition reader used for loading the bean + * definitions of this context. Default implementation is empty. + *

Can be overridden in subclasses, e.g. for turning off XML validation + * or using a different XmlBeanDefinitionParser implementation. + * @param beanDefinitionReader the bean definition reader used by this context + * @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader#setValidationMode + * @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader#setDocumentReaderClass + */ + protected void initBeanDefinitionReader(XmlBeanDefinitionReader beanDefinitionReader) { + } + + /** + * Load the bean definitions with the given XmlBeanDefinitionReader. + *

The lifecycle of the bean factory is handled by the refreshBeanFactory method; + * therefore this method is just supposed to load and/or register bean definitions. + *

Delegates to a ResourcePatternResolver for resolving location patterns + * into Resource instances. + * @throws org.springframework.beans.BeansException in case of bean registration errors + * @throws java.io.IOException if the required XML document isn't found + * @see #refreshBeanFactory + * @see #getConfigLocations + * @see #getResources + * @see #getResourcePatternResolver + */ + protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException { + String[] configLocations = getConfigLocations(); + if (configLocations != null) { + for (int i = 0; i < configLocations.length; i++) { + reader.loadBeanDefinitions(configLocations[i]); + } + } + } + + /** + * The default location for the root context is "/WEB-INF/applicationContext.xml", + * and "/WEB-INF/test-servlet.xml" for a context with the namespace "test-servlet" + * (like for a DispatcherServlet instance with the servlet-name "test"). + */ + protected String[] getDefaultConfigLocations() { + if (getNamespace() != null) { + return new String[] {DEFAULT_CONFIG_LOCATION_PREFIX + getNamespace() + DEFAULT_CONFIG_LOCATION_SUFFIX}; + } + else { + return new String[] {DEFAULT_CONFIG_LOCATION}; + } + } + +} Index: 3rdParty_sources/spring/org/springframework/web/context/support/package.html =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/web/context/support/package.html,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/web/context/support/package.html 17 Aug 2012 15:16:05 -0000 1.1 @@ -0,0 +1,8 @@ + + + +Classes supporting the org.springframework.web.context package, +such as WebApplicationContext implementations and various utility classes. + + + Index: 3rdParty_sources/spring/org/springframework/web/filter/AbstractRequestLoggingFilter.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/web/filter/AbstractRequestLoggingFilter.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/web/filter/AbstractRequestLoggingFilter.java 17 Aug 2012 15:16:18 -0000 1.1 @@ -0,0 +1,231 @@ +/* + * 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.web.filter; + +import java.io.IOException; + +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; + +import org.springframework.util.StringUtils; + +/** + * Base class for Filters that perform logging operations before and after a + * request is processed. + * + *

Subclasses should override the beforeRequest(HttpServletRequest, String) + * and afterRequest(HttpServletRequest, String) methods to perform the actual + * logging around the request. + * + *

Subclasses are passed the message to write to the log in the beforeRequest + * and afterRequest methods. By default, only the URI of the request is logged. + * However, setting the includeQueryString property to true will + * cause the query string of the request to be included also. + * + *

Prefixes and suffixes for the before and after messages can be configured + * using the beforeMessagePrefix, afterMessagePrefix, + * beforeMessageSuffix and afterMessageSuffix properties, + * + * @author Rob Harrop + * @author Juergen Hoeller + * @since 1.2.5 + * @see #beforeRequest + * @see #afterRequest + */ +public abstract class AbstractRequestLoggingFilter extends OncePerRequestFilter { + + public static final String DEFAULT_BEFORE_MESSAGE_PREFIX = "Before request ["; + + public static final String DEFAULT_BEFORE_MESSAGE_SUFFIX = "]"; + + public static final String DEFAULT_AFTER_MESSAGE_PREFIX = "After request ["; + + public static final String DEFAULT_AFTER_MESSAGE_SUFFIX = "]"; + + + private boolean includeQueryString = false; + + private boolean includeClientInfo = false; + + private String beforeMessagePrefix = DEFAULT_BEFORE_MESSAGE_PREFIX; + + private String beforeMessageSuffix = DEFAULT_BEFORE_MESSAGE_SUFFIX; + + private String afterMessagePrefix = DEFAULT_AFTER_MESSAGE_PREFIX; + + private String afterMessageSuffix = DEFAULT_AFTER_MESSAGE_SUFFIX; + + + /** + * Set whether or not the query string should be included in the log message. + *

Should be configured using an <init-param> for parameter + * name "includeQueryString" in the filter definition in web.xml. + */ + public void setIncludeQueryString(boolean includeQueryString) { + this.includeQueryString = includeQueryString; + } + + /** + * Return whether or not the query string should be included in the log message. + */ + protected boolean isIncludeQueryString() { + return this.includeQueryString; + } + + /** + * Set whether or not the client address and session id should be included + * in the log message. + *

Should be configured using an <init-param> for parameter + * name "includeClientInfo" in the filter definition in web.xml. + */ + public void setIncludeClientInfo(boolean includeClientInfo) { + this.includeClientInfo = includeClientInfo; + } + + /** + * Return whether or not the client address and session id should be included + * in the log message. + */ + protected boolean isIncludeClientInfo() { + return this.includeClientInfo; + } + + /** + * Set the value that should be prepended to the log message written + * before a request is processed. + */ + public void setBeforeMessagePrefix(String beforeMessagePrefix) { + this.beforeMessagePrefix = beforeMessagePrefix; + } + + /** + * Set the value that should be apppended to the log message written + * before a request is processed. + */ + public void setBeforeMessageSuffix(String beforeMessageSuffix) { + this.beforeMessageSuffix = beforeMessageSuffix; + } + + /** + * Set the value that should be prepended to the log message written + * after a request is processed. + */ + public void setAfterMessagePrefix(String afterMessagePrefix) { + this.afterMessagePrefix = afterMessagePrefix; + } + + /** + * Set the value that should be appended to the log message written + * after a request is processed. + */ + public void setAfterMessageSuffix(String afterMessageSuffix) { + this.afterMessageSuffix = afterMessageSuffix; + } + + + /** + * Forwards the request to the next filter in the chain and delegates + * down to the subclasses to perform the actual request logging both + * before and after the request is processed. + * @see #beforeRequest + * @see #afterRequest + */ + protected void doFilterInternal( + HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) + throws ServletException, IOException { + + beforeRequest(request, getBeforeMessage(request)); + try { + filterChain.doFilter(request, response); + } + finally { + afterRequest(request, getAfterMessage(request)); + } + } + + + /** + * Get the message to write to the log before the request. + * @see #createMessage + */ + private String getBeforeMessage(HttpServletRequest request) { + return createMessage(request, this.beforeMessagePrefix, this.beforeMessageSuffix); + } + + /** + * Get the message to write to the log after the request. + * @see #createMessage + */ + private String getAfterMessage(HttpServletRequest request) { + return createMessage(request, this.afterMessagePrefix, this.afterMessageSuffix); + } + + /** + * Create a log message for the given request, prefix and suffix. + *

If includeQueryString is true then + * the inner part of the log message will take the form + * request_uri?query_string otherwise the message will + * simply be of the form request_uri. + *

The final message is composed of the inner part as described + * and the supplied prefix and suffix. + */ + protected String createMessage(HttpServletRequest request, String prefix, String suffix) { + StringBuffer buffer = new StringBuffer(); + buffer.append(prefix); + buffer.append("uri=").append(request.getRequestURI()); + if (isIncludeQueryString()) { + buffer.append('?').append(request.getQueryString()); + } + if (isIncludeClientInfo()) { + String client = request.getRemoteAddr(); + if (StringUtils.hasLength(client)) { + buffer.append(";client=").append(client); + } + HttpSession session = request.getSession(false); + if (session != null) { + buffer.append(";session=").append(session.getId()); + } + String user = request.getRemoteUser(); + if (user != null) { + buffer.append(";user=").append(user); + } + } + buffer.append(suffix); + return buffer.toString(); + } + + + /** + * Concrete subclasses should implement this method to write a log message + * before the request is processed. + * @param request current HTTP request + * @param message the message to log + */ + protected abstract void beforeRequest(HttpServletRequest request, String message); + + /** + * Concrete subclasses should implement this method to write a log message + * after the request is processed. + * @param request current HTTP request + * @param message the message to log + */ + protected abstract void afterRequest(HttpServletRequest request, String message); + +} Index: 3rdParty_sources/spring/org/springframework/web/filter/CharacterEncodingFilter.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/web/filter/CharacterEncodingFilter.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/web/filter/CharacterEncodingFilter.java 17 Aug 2012 15:16:18 -0000 1.1 @@ -0,0 +1,99 @@ +/* + * 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.web.filter; + +import java.io.IOException; + +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.springframework.util.ClassUtils; + +/** + * Servlet 2.3/2.4 Filter that allows one to specify a character encoding for + * requests. This is useful because current browsers typically do not set a + * character encoding even if specified in the HTML page or form. + * + *

This filter can either apply its encoding if the request does not + * already specify an encoding, or enforce this filter's encoding in any case + * ("forceEncoding"="true"). In the latter case, the encoding will also be + * applied as default response encoding on Servlet 2.4+ containers (although + * this will usually be overridden by a full content type set in the view). + * + * @author Juergen Hoeller + * @since 15.03.2004 + * @see #setEncoding + * @see #setForceEncoding + * @see javax.servlet.http.HttpServletRequest#setCharacterEncoding + * @see javax.servlet.http.HttpServletResponse#setCharacterEncoding + */ +public class CharacterEncodingFilter extends OncePerRequestFilter { + + // Determine whether the Servlet 2.4 HttpServletResponse.setCharacterEncoding(String) + // method is available, for use in the "doFilterInternal" implementation. + private final static boolean responseSetCharacterEncodingAvailable = ClassUtils.hasMethod( + HttpServletResponse.class, "setCharacterEncoding", new Class[] {String.class}); + + + private String encoding; + + private boolean forceEncoding = false; + + + /** + * Set the encoding to use for requests. This encoding will be passed into a + * {@link javax.servlet.http.HttpServletRequest#setCharacterEncoding} call. + *

Whether this encoding will override existing request encodings + * (and whether it will be applied as default response encoding as well) + * depends on the {@link #setForceEncoding "forceEncoding"} flag. + */ + public void setEncoding(String encoding) { + this.encoding = encoding; + } + + /** + * Set whether the configured {@link #setEncoding encoding} of this filter + * is supposed to override existing request and response encodings. + *

Default is "false", i.e. do not modify the encoding if + * {@link javax.servlet.http.HttpServletRequest#getCharacterEncoding()} + * returns a non-null value. Switch this to "true" to enforce the specified + * encoding in any case, applying it as default response encoding as well. + *

Note that the response encoding will only be set on Servlet 2.4+ + * containers, since Servlet 2.3 did not provide a facility for setting + * a default response encoding. + */ + public void setForceEncoding(boolean forceEncoding) { + this.forceEncoding = forceEncoding; + } + + + protected void doFilterInternal( + HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) + throws ServletException, IOException { + + if (this.encoding != null && (this.forceEncoding || request.getCharacterEncoding() == null)) { + request.setCharacterEncoding(this.encoding); + if (this.forceEncoding && responseSetCharacterEncodingAvailable) { + response.setCharacterEncoding(this.encoding); + } + } + filterChain.doFilter(request, response); + } + +} Index: 3rdParty_sources/spring/org/springframework/web/filter/CommonsRequestLoggingFilter.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/web/filter/CommonsRequestLoggingFilter.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/web/filter/CommonsRequestLoggingFilter.java 17 Aug 2012 15:16:18 -0000 1.1 @@ -0,0 +1,54 @@ +/* + * 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.web.filter; + +import javax.servlet.http.HttpServletRequest; + +/** + * Simple request logging filter that writes the request URI + * (and optionally the query string) to the Commons Log. + * + * @author Rob Harrop + * @since 1.2.5 + * @see #setIncludeQueryString + * @see #setBeforeMessagePrefix + * @see #setBeforeMessageSuffix + * @see #setAfterMessagePrefix + * @see #setAfterMessageSuffix + * @see org.apache.commons.logging.Log#debug(Object) + */ +public class CommonsRequestLoggingFilter extends AbstractRequestLoggingFilter { + + /** + * Writes a log message before the request is processed. + */ + protected void beforeRequest(HttpServletRequest request, String message) { + if (logger.isDebugEnabled()) { + logger.debug(message); + } + } + + /** + * Writes a log message after the request is processed. + */ + protected void afterRequest(HttpServletRequest request, String message) { + if (logger.isDebugEnabled()) { + logger.debug(message); + } + } + +} Index: 3rdParty_sources/spring/org/springframework/web/filter/DelegatingFilterProxy.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/web/filter/DelegatingFilterProxy.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/web/filter/DelegatingFilterProxy.java 17 Aug 2012 15:16:18 -0000 1.1 @@ -0,0 +1,252 @@ +/* + * 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.web.filter; + +import java.io.IOException; + +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; + +import org.springframework.web.context.WebApplicationContext; +import org.springframework.web.context.support.WebApplicationContextUtils; + +/** + * Proxy for a standard Servlet 2.3 Filter, delegating to a Spring-managed + * bean that implements the Filter interface. Supports a "targetBeanName" + * filter init-param in web.xml, specifying the name of the + * target bean in the Spring application context. + * + *

web.xml will usually contain a DelegatingFilterProxy definition, + * with the specified filter-name corresponding to a bean name in + * Spring's root application context. All calls to the filter proxy will then + * be delegated to that bean in the Spring context, which is required to implement + * the standard Servlet 2.3 Filter interface. + * + *

This approach is particularly useful for Filter implementation with complex + * setup needs, allowing to apply the full Spring bean definition machinery to + * Filter instances. Alternatively, consider standard Filter setup in combination + * with looking up service beans from the Spring root application context. + * + *

NOTE: The lifecycle methods defined by the Servlet Filter interface + * will by default not be delegated to the target bean, relying on the + * Spring application context to manage the lifecycle of that bean. Specifying + * the "targetFilterLifecycle" filter init-param as "true" will enforce invocation + * of the Filter.init and Filter.destroy lifecycle methods + * on the target bean, letting the servlet container manage the filter lifecycle. + * + *

This class is inspired by Acegi Security's FilterToBeanProxy class, + * written by Ben Alex. + * + * @author Juergen Hoeller + * @author Sam Brannen + * @since 1.2 + * @see #setTargetBeanName + * @see #setTargetFilterLifecycle + * @see javax.servlet.Filter#doFilter + * @see javax.servlet.Filter#init + * @see javax.servlet.Filter#destroy + */ +public class DelegatingFilterProxy extends GenericFilterBean { + + private String contextAttribute; + + private String targetBeanName; + + private boolean targetFilterLifecycle = false; + + private Filter delegate; + + private final Object delegateMonitor = new Object(); + + + /** + * Set the name of the ServletContext attribute which should be used to retrieve the + * {@link WebApplicationContext} from which to load the delegate {@link Filter} bean. + */ + public void setContextAttribute(String contextAttribute) { + this.contextAttribute = contextAttribute; + } + + /** + * Return the name of the ServletContext attribute which should be used to retrieve the + * {@link WebApplicationContext} from which to load the delegate {@link Filter} bean. + */ + public String getContextAttribute() { + return this.contextAttribute; + } + + /** + * Set the name of the target bean in the Spring application context. + * The target bean must implement the standard Servlet 2.3 Filter interface. + *

By default, the filter-name as specified for the + * DelegatingFilterProxy in web.xml will be used. + */ + public void setTargetBeanName(String targetBeanName) { + this.targetBeanName = targetBeanName; + } + + /** + * Return the name of the target bean in the Spring application context. + */ + protected String getTargetBeanName() { + return this.targetBeanName; + } + + /** + * Set whether to invoke the Filter.init and + * Filter.destroy lifecycle methods on the target bean. + *

Default is "false"; target beans usually rely on the Spring application + * context for managing their lifecycle. Setting this flag to "true" means + * that the servlet container will control the lifecycle of the target + * Filter, with this proxy delegating the corresponding calls. + */ + public void setTargetFilterLifecycle(boolean targetFilterLifecycle) { + this.targetFilterLifecycle = targetFilterLifecycle; + } + + /** + * Return whether to invoke the Filter.init and + * Filter.destroy lifecycle methods on the target bean. + */ + protected boolean isTargetFilterLifecycle() { + return this.targetFilterLifecycle; + } + + + protected void initFilterBean() throws ServletException { + // If no target bean name specified, use filter name. + if (this.targetBeanName == null) { + this.targetBeanName = getFilterName(); + } + + // Fetch Spring root application context and initialize the delegate early, + // if possible. If the root application context will be started after this + // filter proxy, we'll have to resort to lazy initialization. + synchronized (this.delegateMonitor) { + WebApplicationContext wac = findWebApplicationContext(); + if (wac != null) { + this.delegate = initDelegate(wac); + } + } + } + + public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) + throws ServletException, IOException { + + // Lazily initialize the delegate if necessary. + Filter delegateToUse = null; + synchronized (this.delegateMonitor) { + if (this.delegate == null) { + WebApplicationContext wac = findWebApplicationContext(); + if (wac == null) { + throw new IllegalStateException("No WebApplicationContext found: no ContextLoaderListener registered?"); + } + this.delegate = initDelegate(wac); + } + delegateToUse = this.delegate; + } + + // Let the delegate perform the actual doFilter operation. + invokeDelegate(delegateToUse, request, response, filterChain); + } + + public void destroy() { + Filter delegateToUse = null; + synchronized (this.delegateMonitor) { + delegateToUse = this.delegate; + } + if (delegateToUse != null) { + destroyDelegate(delegateToUse); + } + } + + + /** + * Retrieve a WebApplicationContext from the ServletContext + * attribute with the {@link #setContextAttribute configured name}. The + * WebApplicationContext must have already been loaded and stored in the + * ServletContext before this filter gets initialized (or invoked). + *

Subclasses may override this method to provide a different + * WebApplicationContext retrieval strategy. + * @return the WebApplicationContext for this proxy, or null if not found + * @see #getContextAttribute() + */ + protected WebApplicationContext findWebApplicationContext() { + String attrName = getContextAttribute(); + if (attrName != null) { + return WebApplicationContextUtils.getWebApplicationContext(getServletContext(), attrName); + } + else { + return WebApplicationContextUtils.getWebApplicationContext(getServletContext()); + } + } + + /** + * Initialize the Filter delegate, defined as bean the given Spring + * application context. + *

Default implementation fetches the bean from the application context + * and calls the standard Filter.init method on it, passing + * in the FilterConfig of this Filter proxy. + * @param wac the root application context + * @return the initialized delegate Filter + * @throws ServletException if thrown by the Filter + * @see #getTargetBeanName() + * @see #isTargetFilterLifecycle() + * @see #getFilterConfig() + * @see javax.servlet.Filter#init(javax.servlet.FilterConfig) + */ + protected Filter initDelegate(WebApplicationContext wac) throws ServletException { + Filter delegate = (Filter) wac.getBean(getTargetBeanName(), Filter.class); + if (isTargetFilterLifecycle()) { + delegate.init(getFilterConfig()); + } + return delegate; + } + + /** + * Actually invoke the delegate Filter with the given request and response. + * @param delegate the delegate Filter + * @param request the current HTTP request + * @param response the current HTTP response + * @param filterChain the current FilterChain + * @throws ServletException if thrown by the Filter + * @throws IOException if thrown by the Filter + */ + protected void invokeDelegate( + Filter delegate, ServletRequest request, ServletResponse response, FilterChain filterChain) + throws ServletException, IOException { + + delegate.doFilter(request, response, filterChain); + } + + /** + * Destroy the Filter delegate. + * Default implementation simply calls Filter.destroy on it. + * @param delegate the Filter delegate (never null) + * @see #isTargetFilterLifecycle() + * @see javax.servlet.Filter#destroy() + */ + protected void destroyDelegate(Filter delegate) { + if (isTargetFilterLifecycle()) { + delegate.destroy(); + } + } + +} Index: 3rdParty_sources/spring/org/springframework/web/filter/GenericFilterBean.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/web/filter/GenericFilterBean.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/web/filter/GenericFilterBean.java 17 Aug 2012 15:16:18 -0000 1.1 @@ -0,0 +1,304 @@ +/* + * 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.web.filter; + +import java.util.Enumeration; +import java.util.HashSet; +import java.util.Set; + +import javax.servlet.Filter; +import javax.servlet.FilterConfig; +import javax.servlet.ServletContext; +import javax.servlet.ServletException; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import org.springframework.beans.BeanWrapper; +import org.springframework.beans.BeansException; +import org.springframework.beans.MutablePropertyValues; +import org.springframework.beans.PropertyAccessorFactory; +import org.springframework.beans.PropertyValue; +import org.springframework.beans.PropertyValues; +import org.springframework.beans.factory.BeanNameAware; +import org.springframework.beans.factory.DisposableBean; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.core.io.Resource; +import org.springframework.core.io.ResourceEditor; +import org.springframework.core.io.ResourceLoader; +import org.springframework.util.Assert; +import org.springframework.util.StringUtils; +import org.springframework.web.context.ServletContextAware; +import org.springframework.web.context.support.ServletContextResourceLoader; +import org.springframework.web.util.NestedServletException; + +/** + * Simple base implementation of {@link javax.servlet.Filter} which treats + * its config parameters (init-param entries within the + * filter tag in web.xml) as bean properties. + * + *

A handy superclass for any type of filter. Type conversion of config + * parameters is automatic, with the corresponding setter method getting + * invoked with the converted value. It is also possible for subclasses to + * specify required properties. Parameters without matching bean property + * setter will simply be ignored. + * + *

This filter leaves actual filtering to subclasses, which have to + * implement the {@link javax.servlet.Filter#doFilter} method. + * + *

This generic filter base class has no dependency on the Spring + * {@link org.springframework.context.ApplicationContext} concept. + * Filters usually don't load their own context but rather access service + * beans from the Spring root application context, accessible via the + * filter's {@link #getServletContext() ServletContext} (see + * {@link org.springframework.web.context.support.WebApplicationContextUtils}). + * + * @author Juergen Hoeller + * @since 06.12.2003 + * @see #addRequiredProperty + * @see #initFilterBean + * @see #doFilter + */ +public abstract class GenericFilterBean implements + Filter, BeanNameAware, ServletContextAware, InitializingBean, DisposableBean { + + /** Logger available to subclasses */ + protected final Log logger = LogFactory.getLog(getClass()); + + /** + * Set of required properties (Strings) that must be supplied as + * config parameters to this filter. + */ + private final Set requiredProperties = new HashSet(); + + /* The FilterConfig of this filter */ + private FilterConfig filterConfig; + + + private String beanName; + + private ServletContext servletContext; + + + /** + * Stores the bean name as defined in the Spring bean factory. + *

Only relevant in case of initialization as bean, to have a name as + * fallback to the filter name usually provided by a FilterConfig instance. + * @see org.springframework.beans.factory.BeanNameAware + * @see #getFilterName() + */ + public final void setBeanName(String beanName) { + this.beanName = beanName; + } + + /** + * Stores the ServletContext that the bean factory runs in. + *

Only relevant in case of initialization as bean, to have a ServletContext + * as fallback to the context usually provided by a FilterConfig instance. + * @see org.springframework.web.context.ServletContextAware + * @see #getServletContext() + */ + public final void setServletContext(ServletContext servletContext) { + this.servletContext = servletContext; + } + + /** + * Calls the initFilterBean() method that might + * contain custom initialization of a subclass. + *

Only relevant in case of initialization as bean, where the + * standard init(FilterConfig) method won't be called. + * @see #initFilterBean() + * @see #init(javax.servlet.FilterConfig) + */ + public void afterPropertiesSet() throws ServletException { + initFilterBean(); + } + + + /** + * Subclasses can invoke this method to specify that this property + * (which must match a JavaBean property they expose) is mandatory, + * and must be supplied as a config parameter. This should be called + * from the constructor of a subclass. + *

This method is only relevant in case of traditional initialization + * driven by a FilterConfig instance. + * @param property name of the required property + */ + protected final void addRequiredProperty(String property) { + this.requiredProperties.add(property); + } + + /** + * Standard way of initializing this filter. + * Map config parameters onto bean properties of this filter, and + * invoke subclass initialization. + * @param filterConfig the configuration for this filter + * @throws ServletException if bean properties are invalid (or required + * properties are missing), or if subclass initialization fails. + * @see #initFilterBean + */ + public final void init(FilterConfig filterConfig) throws ServletException { + Assert.notNull(filterConfig, "FilterConfig must not be null"); + if (logger.isDebugEnabled()) { + logger.debug("Initializing filter '" + filterConfig.getFilterName() + "'"); + } + + this.filterConfig = filterConfig; + + // Set bean properties from init parameters. + try { + PropertyValues pvs = new FilterConfigPropertyValues(filterConfig, this.requiredProperties); + BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this); + ResourceLoader resourceLoader = new ServletContextResourceLoader(filterConfig.getServletContext()); + bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader)); + initBeanWrapper(bw); + bw.setPropertyValues(pvs, true); + } + catch (BeansException ex) { + String msg = "Failed to set bean properties on filter '" + + filterConfig.getFilterName() + "': " + ex.getMessage(); + logger.error(msg, ex); + throw new NestedServletException(msg, ex); + } + + // Let subclasses do whatever initialization they like. + initFilterBean(); + + if (logger.isDebugEnabled()) { + logger.debug("Filter '" + filterConfig.getFilterName() + "' configured successfully"); + } + } + + /** + * Initialize the BeanWrapper for this GenericFilterBean, + * possibly with custom editors. + *

This default implementation is empty. + * @param bw the BeanWrapper to initialize + * @throws BeansException if thrown by BeanWrapper methods + * @see org.springframework.beans.BeanWrapper#registerCustomEditor + */ + protected void initBeanWrapper(BeanWrapper bw) throws BeansException { + } + + + /** + * Make the FilterConfig of this filter available, if any. + * Analogous to GenericServlet's getServletConfig(). + *

Public to resemble the getFilterConfig() method + * of the Servlet Filter version that shipped with WebLogic 6.1. + * @return the FilterConfig instance, or null if none available + * @see javax.servlet.GenericServlet#getServletConfig() + */ + public final FilterConfig getFilterConfig() { + return this.filterConfig; + } + + /** + * Make the name of this filter available to subclasses. + * Analogous to GenericServlet's getServletName(). + *

Takes the FilterConfig's filter name by default. + * If initialized as bean in a Spring application context, + * it falls back to the bean name as defined in the bean factory. + * @return the filter name, or null if none available + * @see javax.servlet.GenericServlet#getServletName() + * @see javax.servlet.FilterConfig#getFilterName() + * @see #setBeanName + */ + protected final String getFilterName() { + return (this.filterConfig != null ? this.filterConfig.getFilterName() : this.beanName); + } + + /** + * Make the ServletContext of this filter available to subclasses. + * Analogous to GenericServlet's getServletContext(). + *

Takes the FilterConfig's ServletContext by default. + * If initialized as bean in a Spring application context, + * it falls back to the ServletContext that the bean factory runs in. + * @return the ServletContext instance, or null if none available + * @see javax.servlet.GenericServlet#getServletContext() + * @see javax.servlet.FilterConfig#getServletContext() + * @see #setServletContext + */ + protected final ServletContext getServletContext() { + return (this.filterConfig != null ? this.filterConfig.getServletContext() : this.servletContext); + } + + + /** + * Subclasses may override this to perform custom initialization. + * All bean properties of this filter will have been set before this + * method is invoked. + *

Note: This method will be called from standard filter initialization + * as well as filter bean initialization in a Spring application context. + * Filter name and ServletContext will be available in both cases. + *

This default implementation is empty. + * @throws ServletException if subclass initialization fails + * @see #getFilterName() + * @see #getServletContext() + */ + protected void initFilterBean() throws ServletException { + } + + /** + * Subclasses may override this to perform custom filter shutdown. + *

Note: This method will be called from standard filter destruction + * as well as filter bean destruction in a Spring application context. + *

This default implementation is empty. + */ + public void destroy() { + } + + + /** + * PropertyValues implementation created from FilterConfig init parameters. + */ + private static class FilterConfigPropertyValues extends MutablePropertyValues { + + /** + * Create new FilterConfigPropertyValues. + * @param config FilterConfig we'll use to take PropertyValues from + * @param requiredProperties set of property names we need, where + * we can't accept default values + * @throws ServletException if any required properties are missing + */ + public FilterConfigPropertyValues(FilterConfig config, Set requiredProperties) + throws ServletException { + + Set missingProps = (requiredProperties != null && !requiredProperties.isEmpty()) ? + new HashSet(requiredProperties) : null; + + Enumeration en = config.getInitParameterNames(); + while (en.hasMoreElements()) { + String property = (String) en.nextElement(); + Object value = config.getInitParameter(property); + addPropertyValue(new PropertyValue(property, value)); + if (missingProps != null) { + missingProps.remove(property); + } + } + + // Fail if we are still missing properties. + if (missingProps != null && missingProps.size() > 0) { + throw new ServletException( + "Initialization from FilterConfig for filter '" + config.getFilterName() + + "' failed; the following required properties were missing: " + + StringUtils.collectionToDelimitedString(missingProps, ", ")); + } + } + } + +} Index: 3rdParty_sources/spring/org/springframework/web/filter/Log4jNestedDiagnosticContextFilter.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/web/filter/Log4jNestedDiagnosticContextFilter.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/web/filter/Log4jNestedDiagnosticContextFilter.java 17 Aug 2012 15:16:18 -0000 1.1 @@ -0,0 +1,82 @@ +/* + * 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.web.filter; + +import javax.servlet.http.HttpServletRequest; + +import org.apache.log4j.Logger; +import org.apache.log4j.NDC; + +/** + * Request logging filter that adds the request log message to the Log4J + * nested diagnostic context (NDC) before the request is processed, + * removing it again after the request is processed. + * + * @author Juergen Hoeller + * @author Rob Harrop + * @since 1.2.5 + * @see #setIncludeQueryString + * @see #setBeforeMessagePrefix + * @see #setBeforeMessageSuffix + * @see #setAfterMessagePrefix + * @see #setAfterMessageSuffix + * @see org.apache.log4j.NDC#push(String) + * @see org.apache.log4j.NDC#pop() + */ +public class Log4jNestedDiagnosticContextFilter extends AbstractRequestLoggingFilter { + + /** Logger available to subclasses */ + protected final Logger log4jLogger = Logger.getLogger(getClass()); + + + /** + * Logs the before-request message through Log4J and + * adds a message the Log4J NDC before the request is processed. + */ + protected void beforeRequest(HttpServletRequest request, String message) { + if (log4jLogger.isDebugEnabled()) { + log4jLogger.debug(message); + } + NDC.push(getNestedDiagnosticContextMessage(request)); + } + + /** + * Determine the message to be pushed onto the Log4J nested diagnostic context. + *

Default is a plain request log message without prefix or suffix. + * @param request current HTTP request + * @return the message to be pushed onto the Log4J NDC + * @see #createMessage + */ + protected String getNestedDiagnosticContextMessage(HttpServletRequest request) { + return createMessage(request, "", ""); + } + + /** + * Removes the log message from the Log4J NDC after the request is processed + * and logs the after-request message through Log4J. + */ + protected void afterRequest(HttpServletRequest request, String message) { + NDC.pop(); + if (NDC.getDepth() == 0) { + NDC.remove(); + } + if (log4jLogger.isDebugEnabled()) { + log4jLogger.debug(message); + } + } + +} Index: 3rdParty_sources/spring/org/springframework/web/filter/OncePerRequestFilter.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/web/filter/OncePerRequestFilter.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/web/filter/OncePerRequestFilter.java 17 Aug 2012 15:16:17 -0000 1.1 @@ -0,0 +1,125 @@ +/* + * 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.web.filter; + +import java.io.IOException; + +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +/** + * Filter base class that guarantees to be just executed once per request, + * on any servlet container. It provides a {@link #doFilterInternal} + * method with HttpServletRequest and HttpServletResponse arguments. + * + *

The {@link #getAlreadyFilteredAttributeName} method determines how + * to identify that a request is already filtered. The default implementation + * is based on the configured name of the concrete filter instance. + * + * @author Juergen Hoeller + * @since 06.12.2003 + */ +public abstract class OncePerRequestFilter extends GenericFilterBean { + + /** + * Suffix that gets appended to the filter name for the + * "already filtered" request attribute. + * @see #getAlreadyFilteredAttributeName + */ + public static final String ALREADY_FILTERED_SUFFIX = ".FILTERED"; + + + /** + * This doFilter implementation stores a request attribute for + * "already filtered", proceeding without filtering again if the + * attribute is already there. + * @see #getAlreadyFilteredAttributeName + * @see #shouldNotFilter + * @see #doFilterInternal + */ + public final void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) + throws ServletException, IOException { + + if (!(request instanceof HttpServletRequest) || !(response instanceof HttpServletResponse)) { + throw new ServletException("OncePerRequestFilter just supports HTTP requests"); + } + HttpServletRequest httpRequest = (HttpServletRequest) request; + HttpServletResponse httpResponse = (HttpServletResponse) response; + + String alreadyFilteredAttributeName = getAlreadyFilteredAttributeName(); + if (request.getAttribute(alreadyFilteredAttributeName) != null || shouldNotFilter(httpRequest)) { + // Proceed without invoking this filter... + filterChain.doFilter(request, response); + } + else { + // Do invoke this filter... + request.setAttribute(alreadyFilteredAttributeName, Boolean.TRUE); + try { + doFilterInternal(httpRequest, httpResponse, filterChain); + } + finally { + // Remove the "already filtered" request attribute for this request. + request.removeAttribute(alreadyFilteredAttributeName); + } + } + } + + /** + * Return the name of the request attribute that identifies that a request + * is already filtered. + *

Default implementation takes the configured name of the concrete filter + * instance and appends ".FILTERED". If the filter is not fully initialized, + * it falls back to its class name. + * @see #getFilterName + * @see #ALREADY_FILTERED_SUFFIX + */ + protected String getAlreadyFilteredAttributeName() { + String name = getFilterName(); + if (name == null) { + name = getClass().getName(); + } + return name + ALREADY_FILTERED_SUFFIX; + } + + /** + * Can be overridden in subclasses for custom filtering control, + * returning true to avoid filtering of the given request. + *

The default implementation always returns false. + * @param request current HTTP request + * @return whether the given request should not be filtered + * @throws ServletException in case of errors + */ + protected boolean shouldNotFilter(HttpServletRequest request) throws ServletException { + return false; + } + + + /** + * Same contract as for doFilter, but guaranteed to be + * just invoked once per request. Provides HttpServletRequest and + * HttpServletResponse arguments instead of the default ServletRequest + * and ServletResponse ones. + */ + protected abstract void doFilterInternal( + HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) + throws ServletException, IOException; + +} Index: 3rdParty_sources/spring/org/springframework/web/filter/RequestContextFilter.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/web/filter/RequestContextFilter.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/web/filter/RequestContextFilter.java 17 Aug 2012 15:16:18 -0000 1.1 @@ -0,0 +1,95 @@ +/* + * 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.web.filter; + +import java.io.IOException; + +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.springframework.context.i18n.LocaleContextHolder; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; + +/** + * Servlet 2.3 Filter that exposes the request to the current thread, + * through both {@link org.springframework.context.i18n.LocaleContextHolder} and + * {@link RequestContextHolder}. To be registered as filter in web.xml. + * + *

Alternatively, Spring's {@link org.springframework.web.context.request.RequestContextListener} + * and Spring's {@link org.springframework.web.servlet.DispatcherServlet} also expose + * the same request context to the current thread. + * + *

This filter is mainly for use with third-party servlets, e.g. the JSF FacesServlet. + * Within Spring's own web support, DispatcherServlet's processing is perfectly sufficient. + * + * @author Juergen Hoeller + * @author Rod Johnson + * @since 2.0 + * @see org.springframework.context.i18n.LocaleContextHolder + * @see org.springframework.web.context.request.RequestContextHolder + * @see org.springframework.web.context.request.RequestContextListener + * @see org.springframework.web.servlet.DispatcherServlet + */ +public class RequestContextFilter extends OncePerRequestFilter { + + private boolean threadContextInheritable = false; + + + /** + * Set whether to expose the LocaleContext and RequestAttributes as inheritable + * for child threads (using an {@link java.lang.InheritableThreadLocal}). + *

Default is "false", to avoid side effects on spawned background threads. + * Switch this to "true" to enable inheritance for custom child threads which + * are spawned during request processing and only used for this request + * (that is, ending after their initial task, without reuse of the thread). + *

WARNING: Do not use inheritance for child threads if you are + * accessing a thread pool which is configured to potentially add new threads + * on demand (e.g. a JDK {@link java.util.concurrent.ThreadPoolExecutor}), + * since this will expose the inherited context to such a pooled thread. + */ + public void setThreadContextInheritable(boolean threadContextInheritable) { + this.threadContextInheritable = threadContextInheritable; + } + + + protected void doFilterInternal( + HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) + throws ServletException, IOException { + + ServletRequestAttributes attributes = new ServletRequestAttributes(request); + LocaleContextHolder.setLocale(request.getLocale(), this.threadContextInheritable); + RequestContextHolder.setRequestAttributes(attributes, this.threadContextInheritable); + if (logger.isDebugEnabled()) { + logger.debug("Bound request context to thread: " + request); + } + try { + filterChain.doFilter(request, response); + } + finally { + RequestContextHolder.resetRequestAttributes(); + LocaleContextHolder.resetLocaleContext(); + attributes.requestCompleted(); + if (logger.isDebugEnabled()) { + logger.debug("Cleared thread-bound request context: " + request); + } + } + } + +} Index: 3rdParty_sources/spring/org/springframework/web/filter/ServletContextRequestLoggingFilter.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/web/filter/ServletContextRequestLoggingFilter.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/web/filter/ServletContextRequestLoggingFilter.java 17 Aug 2012 15:16:18 -0000 1.1 @@ -0,0 +1,50 @@ +/* + * 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.web.filter; + +import javax.servlet.http.HttpServletRequest; + +/** + * Simple request logging filter that writes the request URI + * (and optionally the query string) to the ServletContext log. + * + * @author Juergen Hoeller + * @since 1.2.5 + * @see #setIncludeQueryString + * @see #setBeforeMessagePrefix + * @see #setBeforeMessageSuffix + * @see #setAfterMessagePrefix + * @see #setAfterMessageSuffix + * @see javax.servlet.ServletContext#log(String) + */ +public class ServletContextRequestLoggingFilter extends AbstractRequestLoggingFilter { + + /** + * Writes a log message before the request is processed. + */ + protected void beforeRequest(HttpServletRequest request, String message) { + getServletContext().log(message); + } + + /** + * Writes a log message after the request is processed. + */ + protected void afterRequest(HttpServletRequest request, String message) { + getServletContext().log(message); + } + +} Index: 3rdParty_sources/spring/org/springframework/web/filter/package.html =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/web/filter/package.html,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/web/filter/package.html 17 Aug 2012 15:16:18 -0000 1.1 @@ -0,0 +1,7 @@ + + + +Provides generic filter base classes allowing for bean-style configuration. + + + Index: 3rdParty_sources/spring/org/springframework/web/jsf/DecoratingNavigationHandler.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/web/jsf/DecoratingNavigationHandler.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/web/jsf/DecoratingNavigationHandler.java 17 Aug 2012 15:16:11 -0000 1.1 @@ -0,0 +1,151 @@ +/* + * 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.web.jsf; + +import javax.faces.application.NavigationHandler; +import javax.faces.context.FacesContext; + +/** + * Base class for JSF NavigationHandler implementations that want + * to be capable of decorating an original NavigationHandler. + * + *

Supports the standard JSF style of decoration (through a constructor argument) + * as well as an overloaded handleNavigation method with explicit + * NavigationHandler argument (passing in the original NavigationHandler). Subclasses + * are forced to implement this overloaded handleNavigation method. + * Standard JSF invocations will automatically delegate to the overloaded method, + * with the constructor-injected NavigationHandler as argument. + * + * @author Juergen Hoeller + * @since 1.2.7 + * @see DelegatingNavigationHandlerProxy + */ +public abstract class DecoratingNavigationHandler extends NavigationHandler { + + private NavigationHandler decoratedNavigationHandler; + + + /** + * Create a DecoratingNavigationHandler without fixed original NavigationHandler. + */ + protected DecoratingNavigationHandler() { + } + + /** + * Create a DecoratingNavigationHandler with fixed original NavigationHandler. + * @param originalNavigationHandler the original NavigationHandler to decorate + */ + protected DecoratingNavigationHandler(NavigationHandler originalNavigationHandler) { + this.decoratedNavigationHandler = originalNavigationHandler; + } + + /** + * Return the fixed original NavigationHandler decorated by this handler, if any + * (that is, if passed in through the constructor). + */ + public final NavigationHandler getDecoratedNavigationHandler() { + return decoratedNavigationHandler; + } + + + /** + * This implementation of the standard JSF handleNavigation method + * delegates to the overloaded variant, passing in constructor-injected + * NavigationHandler as argument. + * @see #handleNavigation(javax.faces.context.FacesContext, String, String, javax.faces.application.NavigationHandler) + */ + public final void handleNavigation(FacesContext facesContext, String fromAction, String outcome) { + handleNavigation(facesContext, fromAction, outcome, this.decoratedNavigationHandler); + } + + /** + * Special handleNavigation variant with explicit NavigationHandler + * argument. Either called directly, by code with an explicit original handler, + * or called from the standard handleNavigation method, as + * plain JSF-defined NavigationHandler. + *

Implementations should invoke callNextHandlerInChain to + * delegate to the next handler in the chain. This will always call the most + * appropriate next handler (see callNextHandlerInChain javadoc). + * Alternatively, the decorated NavigationHandler or the passed-in original + * NavigationHandler can also be called directly; however, this is not as + * flexible in terms of reacting to potential positions in the chain. + * @param facesContext the current JSF context + * @param fromAction the action binding expression that was evaluated to retrieve the + * specified outcome, or null if the outcome was acquired by some other means + * @param outcome the logical outcome returned by a previous invoked application action + * (which may be null) + * @param originalNavigationHandler the original NavigationHandler, + * or null if none + * @see #callNextHandlerInChain + */ + public abstract void handleNavigation( + FacesContext facesContext, String fromAction, String outcome, NavigationHandler originalNavigationHandler); + + + /** + * Method to be called by subclasses when intending to delegate to the next + * handler in the NavigationHandler chain. Will always call the most + * appropriate next handler, either the decorated NavigationHandler passed + * in as constructor argument or the original NavigationHandler as passed + * into this method - according to the position of this instance in the chain. + *

Will call the decorated NavigationHandler specified as constructor + * argument, if any. In case of a DecoratingNavigationHandler as target, the + * original NavigationHandler as passed into this method will be passed on to + * the next element in the chain: This ensures propagation of the original + * handler that the last element in the handler chain might delegate back to. + * In case of a standard NavigationHandler as target, the original handler + * will simply not get passed on; no delegating back to the original is + * possible further down the chain in that scenario. + *

If no decorated NavigationHandler specified as constructor argument, + * this instance is the last element in the chain. Hence, this method will + * call the original NavigationHandler as passed into this method. If no + * original NavigantionHandler has been passed in (for example if this + * instance is the last element in a chain with standard NavigationHandlers + * as earlier elements), this method corresponds to a no-op. + * @param facesContext the current JSF context + * @param fromAction the action binding expression that was evaluated to retrieve the + * specified outcome, or null if the outcome was acquired by some other means + * @param outcome the logical outcome returned by a previous invoked application action + * (which may be null) + * @param originalNavigationHandler the original NavigationHandler, + * or null if none + */ + protected final void callNextHandlerInChain( + FacesContext facesContext, String fromAction, String outcome, NavigationHandler originalNavigationHandler) { + + NavigationHandler decoratedNavigationHandler = getDecoratedNavigationHandler(); + + if (decoratedNavigationHandler instanceof DecoratingNavigationHandler) { + // DecoratingNavigationHandler specified through constructor argument: + // Call it with original NavigationHandler passed in. + DecoratingNavigationHandler decHandler = (DecoratingNavigationHandler) decoratedNavigationHandler; + decHandler.handleNavigation(facesContext, fromAction, outcome, originalNavigationHandler); + } + else if (decoratedNavigationHandler != null) { + // Standard NavigationHandler specified through constructor argument: + // Call it through standard API, without original NavigationHandler passed in. + // The called handler will not be able to redirect to the original handler. + decoratedNavigationHandler.handleNavigation(facesContext, fromAction, outcome); + } + else if (originalNavigationHandler != null) { + // No NavigationHandler specified through constructor argument: + // Call original handler, marking the end of this chain. + originalNavigationHandler.handleNavigation(facesContext, fromAction, outcome); + } + } + +} Index: 3rdParty_sources/spring/org/springframework/web/jsf/DelegatingNavigationHandlerProxy.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/web/jsf/DelegatingNavigationHandlerProxy.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/web/jsf/DelegatingNavigationHandlerProxy.java 17 Aug 2012 15:16:12 -0000 1.1 @@ -0,0 +1,167 @@ +/* + * 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.web.jsf; + +import javax.faces.application.NavigationHandler; +import javax.faces.context.FacesContext; + +import org.springframework.beans.factory.BeanFactory; +import org.springframework.web.context.WebApplicationContext; + +/** + * JSF NavigationHandler implementation that delegates to a NavigationHandler + * bean obtained from the Spring root WebApplicationContext. + * + *

Configure this handler proxy in your faces-config.xml file + * as follows: + * + *

+ * <application>
+ *   ...
+ *   <navigation-handler>
+ * 	   org.springframework.web.jsf.DelegatingNavigationHandlerProxy
+ *   </navigation-handler>
+ *   ...
+ * </application>
+ * + * By default, the Spring ApplicationContext will be searched for the NavigationHandler + * under the bean name "jsfNavigationHandler". In the simplest case, this is a plain + * Spring bean definition like the following. However, all of Spring's bean configuration + * power can be applied to such a bean, in particular all flavors of dependency injection. + * + *
+ * <bean name="jsfNavigationHandler" class="mypackage.MyNavigationHandler">
+ *   <property name="myProperty" ref="myOtherBean"/>
+ * </bean>
+ * + * The target NavigationHandler bean will typically extend the standard JSF + * NavigationHandler class. However, note that decorating the original + * NavigationHandler (the JSF provider's default handler) is not supported + * in such a scenario, since we can't inject the original handler in standard + * JSF style (that is, as constructor argument). + * + *

For decorating the original NavigationHandler, make sure that your + * target bean extends Spring's DecoratingNavigationHandler class. This + * allows to pass in the original handler as method argument, which this proxy + * automatically detects. Note that a DecoratingNavigationHandler subclass + * will still work as standard JSF NavigationHandler as well! + * + *

This proxy may be subclassed to change the bean name used to search for the + * navigation handler, change the strategy used to obtain the target handler, + * or change the strategy used to access the ApplicationContext (normally obtained + * via {@link FacesContextUtils#getWebApplicationContext(FacesContext)}). + * + * @author Juergen Hoeller + * @author Colin Sampaleanu + * @since 1.2.7 + * @see DecoratingNavigationHandler + */ +public class DelegatingNavigationHandlerProxy extends NavigationHandler { + + /** + * Default name of the target bean in the Spring application context: + * "jsfNavigationHandler" + */ + public final static String DEFAULT_TARGET_BEAN_NAME = "jsfNavigationHandler"; + + private NavigationHandler originalNavigationHandler; + + + /** + * Create a new DelegatingNavigationHandlerProxy. + */ + public DelegatingNavigationHandlerProxy() { + } + + /** + * Create a new DelegatingNavigationHandlerProxy. + * @param originalNavigationHandler the original NavigationHandler + */ + public DelegatingNavigationHandlerProxy(NavigationHandler originalNavigationHandler) { + this.originalNavigationHandler = originalNavigationHandler; + } + + + /** + * Handle the navigation request implied by the specified parameters, + * through delegating to the target bean in the Spring application context. + *

The target bean needs to extend the JSF NavigationHandler class. + * If it extends Spring's DecoratingNavigationHandler, the overloaded + * handleNavigation method with the original NavigationHandler + * as argument will be used. Else, the standard handleNavigation + * method will be called. + */ + public void handleNavigation(FacesContext facesContext, String fromAction, String outcome) { + NavigationHandler handler = getDelegate(facesContext); + if (handler instanceof DecoratingNavigationHandler) { + ((DecoratingNavigationHandler) handler).handleNavigation( + facesContext, fromAction, outcome, this.originalNavigationHandler); + } + else { + handler.handleNavigation(facesContext, fromAction, outcome); + } + } + + /** + * Return the target NavigationHandler to delegate to. + *

By default, a bean with the name "jsfNavigationHandler" is obtained + * from the Spring root WebApplicationContext, for every invocation. + * @param facesContext the current JSF context + * @return the target NavigationHandler to delegate to + * @see #getTargetBeanName + * @see #getBeanFactory + */ + protected NavigationHandler getDelegate(FacesContext facesContext) { + String targetBeanName = getTargetBeanName(facesContext); + return (NavigationHandler) getBeanFactory(facesContext).getBean(targetBeanName, NavigationHandler.class); + } + + /** + * Return the name of the target NavigationHandler bean in the BeanFactory. + * Default is "jsfNavigationHandler". + * @param facesContext the current JSF context + * @return the name of the target bean + */ + protected String getTargetBeanName(FacesContext facesContext) { + return DEFAULT_TARGET_BEAN_NAME; + } + + /** + * Retrieve the Spring BeanFactory to delegate bean name resolution to. + *

Default implementation delegates to getWebApplicationContext. + * Can be overridden to provide an arbitrary BeanFactory reference to resolve + * against; usually, this will be a full Spring ApplicationContext. + * @param facesContext the current JSF context + * @return the Spring BeanFactory (never null) + * @see #getWebApplicationContext + */ + protected BeanFactory getBeanFactory(FacesContext facesContext) { + return getWebApplicationContext(facesContext); + } + + /** + * Retrieve the web application context to delegate bean name resolution to. + *

Default implementation delegates to FacesContextUtils. + * @param facesContext the current JSF context + * @return the Spring web application context (never null) + * @see FacesContextUtils#getRequiredWebApplicationContext + */ + protected WebApplicationContext getWebApplicationContext(FacesContext facesContext) { + return FacesContextUtils.getRequiredWebApplicationContext(facesContext); + } + +} Index: 3rdParty_sources/spring/org/springframework/web/jsf/DelegatingPhaseListenerMulticaster.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/web/jsf/DelegatingPhaseListenerMulticaster.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/web/jsf/DelegatingPhaseListenerMulticaster.java 17 Aug 2012 15:16:12 -0000 1.1 @@ -0,0 +1,125 @@ +/* + * 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.web.jsf; + +import java.util.Collection; +import java.util.Iterator; + +import javax.faces.context.FacesContext; +import javax.faces.event.PhaseEvent; +import javax.faces.event.PhaseId; +import javax.faces.event.PhaseListener; + +import org.springframework.beans.factory.BeanFactoryUtils; +import org.springframework.beans.factory.ListableBeanFactory; +import org.springframework.web.context.WebApplicationContext; + +/** + * JSF PhaseListener implementation that delegates to one or more Spring-managed + * PhaseListener beans coming from the Spring root WebApplicationContext. + * + *

Configure this listener multicaster in your faces-config.xml file + * as follows: + * + *

+ * <application>
+ *   ...
+ *   <phase-listener>
+ *     org.springframework.web.jsf.DelegatingPhaseListenerMulticaster
+ *   </phase-listener>
+ *   ...
+ * </application>
+ * + * The multicaster will delegate all beforePhase and afterPhase + * events to all target PhaseListener beans. By default, those will simply be obtained + * by type: All beans in the Spring root WebApplicationContext that implement the + * PhaseListener interface will be fetched and invoked. + * + *

Note: This multicaster's getPhaseId() method will always return + * ANY_PHASE. The phase id exposed by the target listener beans + * will be ignored; all events will be propagated to all listeners. + * + *

This multicaster may be subclassed to change the strategy used to obtain + * the listener beans, or to change the strategy used to access the ApplicationContext + * (normally obtained via {@link FacesContextUtils#getWebApplicationContext(FacesContext)}). + * + * @author Juergen Hoeller + * @author Colin Sampaleanu + * @since 1.2.7 + */ +public class DelegatingPhaseListenerMulticaster implements PhaseListener { + + public PhaseId getPhaseId() { + return PhaseId.ANY_PHASE; + } + + public void beforePhase(PhaseEvent event) { + Collection listeners = getDelegates(event.getFacesContext()); + Iterator it = listeners.iterator(); + while (it.hasNext()) { + PhaseListener listener = (PhaseListener) it.next(); + listener.beforePhase(event); + } + } + + public void afterPhase(PhaseEvent event) { + Collection listeners = getDelegates(event.getFacesContext()); + Iterator it = listeners.iterator(); + while (it.hasNext()) { + PhaseListener listener = (PhaseListener) it.next(); + listener.afterPhase(event); + } + } + + + /** + * Obtain the delegate PhaseListener beans from the Spring root WebApplicationContext. + * @param facesContext the current JSF context + * @return a Collection of PhaseListener objects + * @see #getBeanFactory + * @see org.springframework.beans.factory.ListableBeanFactory#getBeansOfType(Class) + */ + protected Collection getDelegates(FacesContext facesContext) { + ListableBeanFactory bf = getBeanFactory(facesContext); + return BeanFactoryUtils.beansOfTypeIncludingAncestors(bf, PhaseListener.class, true, false).values(); + } + + /** + * Retrieve the Spring BeanFactory to delegate bean name resolution to. + *

The default implementation delegates to getWebApplicationContext. + * Can be overridden to provide an arbitrary ListableBeanFactory reference to + * resolve against; usually, this will be a full Spring ApplicationContext. + * @param facesContext the current JSF context + * @return the Spring ListableBeanFactory (never null) + * @see #getWebApplicationContext + */ + protected ListableBeanFactory getBeanFactory(FacesContext facesContext) { + return getWebApplicationContext(facesContext); + } + + /** + * Retrieve the web application context to delegate bean name resolution to. + *

The default implementation delegates to FacesContextUtils. + * @param facesContext the current JSF context + * @return the Spring web application context (never null) + * @see FacesContextUtils#getRequiredWebApplicationContext + */ + protected WebApplicationContext getWebApplicationContext(FacesContext facesContext) { + return FacesContextUtils.getRequiredWebApplicationContext(facesContext); + } + +} Index: 3rdParty_sources/spring/org/springframework/web/jsf/DelegatingVariableResolver.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/web/jsf/DelegatingVariableResolver.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/web/jsf/DelegatingVariableResolver.java 17 Aug 2012 15:16:11 -0000 1.1 @@ -0,0 +1,169 @@ +/* + * 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.web.jsf; + +import javax.faces.context.FacesContext; +import javax.faces.el.EvaluationException; +import javax.faces.el.VariableResolver; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import org.springframework.beans.factory.BeanFactory; +import org.springframework.util.Assert; +import org.springframework.web.context.WebApplicationContext; + +/** + * JSF 1.1 VariableResolver that first delegates to the + * original resolver of the underlying JSF implementation (for resolving + * managed-bean objects as defined in faces-config.xml + * as well as well-known implicit EL attributes), then to the Spring + * root WebApplicationContext (for resolving Spring beans). + * + *

Configure this resolver in your faces-config.xml file as follows: + * + *

+ * <application>
+ *   ...
+ *   <variable-resolver>org.springframework.web.jsf.DelegatingVariableResolver</variable-resolver>
+ * </application>
+ * + * All your JSF expressions can then implicitly refer to the names of + * Spring-managed service layer beans, for example in property values of + * JSF-managed beans: + * + *
+ * <managed-bean>
+ *   <managed-bean-name>myJsfManagedBean</managed-bean-name>
+ *   <managed-bean-class>example.MyJsfManagedBean</managed-bean-class>
+ *   <managed-bean-scope>session</managed-bean-scope>
+ *   <managed-property>
+ *     <property-name>mySpringManagedBusinessObject</property-name>
+ *     <value>#{mySpringManagedBusinessObject}</value>
+ *   </managed-property>
+ * </managed-bean>
+ * + * with "mySpringManagedBusinessObject" defined as Spring bean in + * applicationContext.xml: + * + *
+ * <bean id="mySpringManagedBusinessObject" class="example.MySpringManagedBusinessObject">
+ *   ...
+ * </bean>
+ * + * @author Juergen Hoeller + * @since 1.1 + * @see WebApplicationContextVariableResolver + * @see FacesContextUtils#getRequiredWebApplicationContext + */ +public class DelegatingVariableResolver extends VariableResolver { + + /** Logger available to subclasses */ + protected final Log logger = LogFactory.getLog(getClass()); + + protected final VariableResolver originalVariableResolver; + + + /** + * Create a new DelegatingVariableResolver, using the given original VariableResolver. + *

A JSF implementation will automatically pass its original resolver into the + * constructor of a configured resolver, provided that there is a corresponding + * constructor argument. + * @param originalVariableResolver the original VariableResolver + */ + public DelegatingVariableResolver(VariableResolver originalVariableResolver) { + Assert.notNull(originalVariableResolver, "Original JSF VariableResolver must not be null"); + this.originalVariableResolver = originalVariableResolver; + } + + /** + * Return the original JSF VariableResolver that this resolver delegates to. + * Used to resolve standard JSF-managed beans. + */ + protected final VariableResolver getOriginalVariableResolver() { + return this.originalVariableResolver; + } + + + /** + * Delegate to the original VariableResolver first, then try to + * resolve the variable as Spring bean in the root WebApplicationContext. + */ + public Object resolveVariable(FacesContext facesContext, String name) throws EvaluationException { + Object value = resolveOriginal(facesContext, name); + if (value != null) { + return value; + } + Object bean = resolveSpringBean(facesContext, name); + if (bean != null) { + return bean; + } + return null; + } + + /** + * Resolve the attribute via the original JSF VariableResolver. + */ + protected Object resolveOriginal(FacesContext facesContext, String name) { + Object value = getOriginalVariableResolver().resolveVariable(facesContext, name); + if (value != null && logger.isTraceEnabled()) { + logger.trace("Successfully resolved variable '" + name + "' via original VariableResolver"); + } + return value; + } + + /** + * Resolve the attribute as a Spring bean in the ApplicationContext. + */ + protected Object resolveSpringBean(FacesContext facesContext, String name) { + BeanFactory bf = getBeanFactory(facesContext); + if (bf.containsBean(name)) { + if (logger.isTraceEnabled()) { + logger.trace("Successfully resolved variable '" + name + "' in Spring BeanFactory"); + } + return bf.getBean(name); + } + else { + return null; + } + } + + /** + * Retrieve the Spring BeanFactory to delegate bean name resolution to. + *

The default implementation delegates to getWebApplicationContext. + * Can be overridden to provide an arbitrary BeanFactory reference to resolve + * against; usually, this will be a full Spring ApplicationContext. + * @param facesContext the current JSF context + * @return the Spring BeanFactory (never null) + * @see #getWebApplicationContext + */ + protected BeanFactory getBeanFactory(FacesContext facesContext) { + return getWebApplicationContext(facesContext); + } + + /** + * Retrieve the web application context to delegate bean name resolution to. + *

The default implementation delegates to FacesContextUtils. + * @param facesContext the current JSF context + * @return the Spring web application context (never null) + * @see FacesContextUtils#getRequiredWebApplicationContext + */ + protected WebApplicationContext getWebApplicationContext(FacesContext facesContext) { + return FacesContextUtils.getRequiredWebApplicationContext(facesContext); + } + +} Index: 3rdParty_sources/spring/org/springframework/web/jsf/FacesContextUtils.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/web/jsf/FacesContextUtils.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/web/jsf/FacesContextUtils.java 17 Aug 2012 15:16:11 -0000 1.1 @@ -0,0 +1,118 @@ +/* + * 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.web.jsf; + +import javax.faces.context.ExternalContext; +import javax.faces.context.FacesContext; + +import org.springframework.util.Assert; +import org.springframework.web.context.WebApplicationContext; +import org.springframework.web.util.WebUtils; + +/** + * Convenience methods to retrieve the root WebApplicationContext for a given + * FacesContext. This is e.g. useful for accessing a Spring context from + * custom JSF code. + * + *

Analogous to Spring's WebApplicationContextUtils for the ServletContext. + * + * @author Juergen Hoeller + * @since 1.1 + * @see org.springframework.web.context.ContextLoader + * @see org.springframework.web.context.support.WebApplicationContextUtils + */ +public abstract class FacesContextUtils { + + /** + * Find the root WebApplicationContext for this web app, which is + * typically loaded via ContextLoaderListener or ContextLoaderServlet. + *

Will rethrow an exception that happened on root context startup, + * to differentiate between a failed context startup and no context at all. + * @param fc the FacesContext to find the web application context for + * @return the root WebApplicationContext for this web app, or null if none + * @see org.springframework.web.context.WebApplicationContext#ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE + */ + public static WebApplicationContext getWebApplicationContext(FacesContext fc) { + Assert.notNull(fc, "FacesContext must not be null"); + Object attr = fc.getExternalContext().getApplicationMap().get( + WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE); + if (attr == null) { + return null; + } + if (attr instanceof RuntimeException) { + throw (RuntimeException) attr; + } + if (attr instanceof Error) { + throw (Error) attr; + } + if (!(attr instanceof WebApplicationContext)) { + throw new IllegalStateException("Root context attribute is not of type WebApplicationContext: " + attr); + } + return (WebApplicationContext) attr; + } + + /** + * Find the root WebApplicationContext for this web app, which is + * typically loaded via ContextLoaderListener or ContextLoaderServlet. + *

Will rethrow an exception that happened on root context startup, + * to differentiate between a failed context startup and no context at all. + * @param fc the FacesContext to find the web application context for + * @return the root WebApplicationContext for this web app + * @throws IllegalStateException if the root WebApplicationContext could not be found + * @see org.springframework.web.context.WebApplicationContext#ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE + */ + public static WebApplicationContext getRequiredWebApplicationContext(FacesContext fc) + throws IllegalStateException { + + WebApplicationContext wac = getWebApplicationContext(fc); + if (wac == null) { + throw new IllegalStateException("No WebApplicationContext found: no ContextLoaderListener registered?"); + } + return wac; + } + + /** + * Return the best available mutex for the given session: + * that is, an object to synchronize on for the given session. + *

Returns the session mutex attribute if available; usually, + * this means that the HttpSessionMutexListener needs to be defined + * in web.xml. Falls back to the Session reference itself + * if no mutex attribute found. + *

The session mutex is guaranteed to be the same object during + * the entire lifetime of the session, available under the key defined + * by the SESSION_MUTEX_ATTRIBUTE constant. It serves as a + * safe reference to synchronize on for locking on the current session. + *

In many cases, the Session reference itself is a safe mutex + * as well, since it will always be the same object reference for the + * same active logical session. However, this is not guaranteed across + * different servlet containers; the only 100% safe way is a session mutex. + * @param fc the FacesContext to find the session mutex for + * @return the mutex object (never null) + * @see org.springframework.web.util.WebUtils#SESSION_MUTEX_ATTRIBUTE + * @see org.springframework.web.util.HttpSessionMutexListener + */ + public static Object getSessionMutex(FacesContext fc) { + Assert.notNull(fc, "FacesContext must not be null"); + ExternalContext ec = fc.getExternalContext(); + Object mutex = ec.getSessionMap().get(WebUtils.SESSION_MUTEX_ATTRIBUTE); + if (mutex == null) { + mutex = ec.getSession(true); + } + return mutex; + } + +} Index: 3rdParty_sources/spring/org/springframework/web/jsf/SpringBeanVariableResolver.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/web/jsf/SpringBeanVariableResolver.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/web/jsf/SpringBeanVariableResolver.java 17 Aug 2012 15:16:12 -0000 1.1 @@ -0,0 +1,53 @@ +/* + * 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.web.jsf; + +import javax.faces.context.FacesContext; +import javax.faces.el.EvaluationException; +import javax.faces.el.VariableResolver; + +/** + * This is a subclass of the JSF 1.1 {@link DelegatingVariableResolver}, + * letting Spring bean definitions override other attributes of the same name. + * + *

The main purpose of this class is to provide behavior that is analogous + * to the JSF 1.2 {@link org.springframework.web.jsf.el.SpringBeanFacesELResolver}. + * + * @author Juergen Hoeller + * @since 2.5 + * @see WebApplicationContextVariableResolver + * @see FacesContextUtils#getRequiredWebApplicationContext + */ +public class SpringBeanVariableResolver extends DelegatingVariableResolver { + + public SpringBeanVariableResolver(VariableResolver originalVariableResolver) { + super(originalVariableResolver); + } + + public Object resolveVariable(FacesContext facesContext, String name) throws EvaluationException { + Object bean = resolveSpringBean(facesContext, name); + if (bean != null) { + return bean; + } + Object value = resolveOriginal(facesContext, name); + if (value != null) { + return value; + } + return null; + } + +} Index: 3rdParty_sources/spring/org/springframework/web/jsf/WebApplicationContextVariableResolver.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/web/jsf/WebApplicationContextVariableResolver.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/web/jsf/WebApplicationContextVariableResolver.java 17 Aug 2012 15:16:11 -0000 1.1 @@ -0,0 +1,113 @@ +/* + * 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.web.jsf; + +import javax.faces.context.FacesContext; +import javax.faces.el.EvaluationException; +import javax.faces.el.VariableResolver; + +import org.springframework.util.Assert; +import org.springframework.web.context.WebApplicationContext; + +/** + * Special JSF 1.1 VariableResolver that exposes the Spring + * WebApplicationContext instance under a variable named + * "webApplicationContext". + * + *

In contrast to {@link DelegatingVariableResolver}, this VariableResolver + * does not resolve JSF variable names as Spring bean names. It rather + * exposes Spring's root WebApplicationContext itself under a special name. + * JSF-managed beans can then use Spring's WebApplicationContext API to retrieve + * Spring-managed beans, access resources, etc. + * + *

Configure this resolver in your faces-config.xml file as follows: + * + *

+ * <application>
+ *   ...
+ *   <variable-resolver>org.springframework.web.jsf.WebApplicationContextVariableResolver</variable-resolver>
+ * </application>
+ * + * @author Colin Sampaleanu + * @author Juergen Hoeller + * @since 1.2.5 + * @see DelegatingVariableResolver + * @see FacesContextUtils#getWebApplicationContext + */ +public class WebApplicationContextVariableResolver extends VariableResolver { + + /** + * Name of the exposed WebApplicationContext variable: "webApplicationContext". + */ + public static final String WEB_APPLICATION_CONTEXT_VARIABLE_NAME = "webApplicationContext"; + + + protected final VariableResolver originalVariableResolver; + + + /** + * Create a new WebApplicationContextVariableResolver, using the given + * original VariableResolver. + *

A JSF implementation will automatically pass its original resolver into the + * constructor of a configured resolver, provided that there is a corresponding + * constructor argument. + * @param originalVariableResolver the original VariableResolver + */ + public WebApplicationContextVariableResolver(VariableResolver originalVariableResolver) { + Assert.notNull(originalVariableResolver, "Original JSF VariableResolver must not be null"); + this.originalVariableResolver = originalVariableResolver; + } + + /** + * Return the original JSF VariableResolver that this resolver delegates to. + * Used to resolve standard JSF-managed beans. + */ + protected final VariableResolver getOriginalVariableResolver() { + return this.originalVariableResolver; + } + + + /** + * Check for the special "webApplicationContext" variable first, + * then delegate to the original VariableResolver. + *

If no WebApplicationContext is available, all requests + * will be delegated to the original VariableResolver. + */ + public Object resolveVariable(FacesContext context, String name) throws EvaluationException { + Object value = null; + if (WEB_APPLICATION_CONTEXT_VARIABLE_NAME.equals(name)) { + value = getWebApplicationContext(context); + } + if (value == null) { + value = getOriginalVariableResolver().resolveVariable(context, name); + } + return value; + } + + /** + * Retrieve the WebApplicationContext reference to expose. + *

The default implementation delegates to FacesContextUtils, + * returning null if no WebApplicationContext found. + * @param facesContext the current JSF context + * @return the Spring web application context + * @see FacesContextUtils#getWebApplicationContext + */ + protected WebApplicationContext getWebApplicationContext(FacesContext facesContext) { + return FacesContextUtils.getWebApplicationContext(facesContext); + } + +} Index: 3rdParty_sources/spring/org/springframework/web/jsf/package.html =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/web/jsf/package.html,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/web/jsf/package.html 17 Aug 2012 15:16:12 -0000 1.1 @@ -0,0 +1,11 @@ + + + +Support classes for integrating a JSF web tier with a Spring middle tier +which is hosted in a Spring root WebApplicationContext. + +

Supports easy access to beans in the Spring root WebApplicationContext +from JSF EL expressions, for example in property values of JSF-managed beans. + + + Index: 3rdParty_sources/spring/org/springframework/web/jsf/el/SpringBeanFacesELResolver.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/web/jsf/el/SpringBeanFacesELResolver.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/web/jsf/el/SpringBeanFacesELResolver.java 17 Aug 2012 15:16:17 -0000 1.1 @@ -0,0 +1,93 @@ +/* + * 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.web.jsf.el; + +import javax.el.ELContext; +import javax.faces.context.FacesContext; + +import org.springframework.beans.factory.BeanFactory; +import org.springframework.beans.factory.access.el.SpringBeanELResolver; +import org.springframework.web.context.WebApplicationContext; +import org.springframework.web.jsf.FacesContextUtils; + +/** + * JSF 1.2 ELResolver that delegates to the Spring root + * WebApplicationContext, resolving name references to + * Spring-defined beans. + * + *

Configure this resolver in your faces-config.xml file as follows: + * + *

+ * <application>
+ *   ...
+ *   <el-resolver>org.springframework.web.jsf.el.SpringBeanFacesELResolver</el-resolver>
+ * </application>
+ * + * All your JSF expressions can then implicitly refer to the names of + * Spring-managed service layer beans, for example in property values of + * JSF-managed beans: + * + *
+ * <managed-bean>
+ *   <managed-bean-name>myJsfManagedBean</managed-bean-name>
+ *   <managed-bean-class>example.MyJsfManagedBean</managed-bean-class>
+ *   <managed-bean-scope>session</managed-bean-scope>
+ *   <managed-property>
+ *     <property-name>mySpringManagedBusinessObject</property-name>
+ *     <value>#{mySpringManagedBusinessObject}</value>
+ *   </managed-property>
+ * </managed-bean>
+ * + * with "mySpringManagedBusinessObject" defined as Spring bean in + * applicationContext.xml: + * + *
+ * <bean id="mySpringManagedBusinessObject" class="example.MySpringManagedBusinessObject">
+ *   ...
+ * </bean>
+ * + * @author Juergen Hoeller + * @since 2.5 + * @see WebApplicationContextFacesELResolver + * @see org.springframework.web.jsf.FacesContextUtils#getRequiredWebApplicationContext + */ +public class SpringBeanFacesELResolver extends SpringBeanELResolver { + + /** + * This implementation delegates to {@link #getWebApplicationContext}. + * Can be overridden to provide an arbitrary BeanFactory reference to resolve + * against; usually, this will be a full Spring ApplicationContext. + * @param elContext the current JSF ELContext + * @return the Spring BeanFactory (never null) + */ + protected BeanFactory getBeanFactory(ELContext elContext) { + return getWebApplicationContext(elContext); + } + + /** + * Retrieve the web application context to delegate bean name resolution to. + *

The default implementation delegates to FacesContextUtils. + * @param elContext the current JSF ELContext + * @return the Spring web application context (never null) + * @see org.springframework.web.jsf.FacesContextUtils#getRequiredWebApplicationContext + */ + protected WebApplicationContext getWebApplicationContext(ELContext elContext) { + FacesContext facesContext = FacesContext.getCurrentInstance(); + return FacesContextUtils.getRequiredWebApplicationContext(facesContext); + } + +} Index: 3rdParty_sources/spring/org/springframework/web/jsf/el/WebApplicationContextFacesELResolver.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/web/jsf/el/WebApplicationContextFacesELResolver.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/web/jsf/el/WebApplicationContextFacesELResolver.java 17 Aug 2012 15:16:17 -0000 1.1 @@ -0,0 +1,175 @@ +/* + * 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.web.jsf.el; + +import java.beans.FeatureDescriptor; +import java.util.Iterator; + +import javax.el.ELContext; +import javax.el.ELException; +import javax.el.ELResolver; +import javax.faces.context.FacesContext; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import org.springframework.beans.BeansException; +import org.springframework.web.context.WebApplicationContext; +import org.springframework.web.jsf.FacesContextUtils; + +/** + * Special JSF 1.2 ELResolver that exposes the Spring + * WebApplicationContext instance under a variable named + * "webApplicationContext". + * + *

In contrast to {@link SpringBeanFacesELResolver}, this ELResolver variant + * does not resolve JSF variable names as Spring bean names. It rather + * exposes Spring's root WebApplicationContext itself under a special name, + * and is able to resolve "webApplicationContext.mySpringManagedBusinessObject" + * dereferences to Spring-defined beans in that application context. + * + *

Configure this resolver in your faces-config.xml file as follows: + * + *

+ * <application>
+ *   ...
+ *   <el-resolver>org.springframework.web.jsf.el.WebApplicationContextFacesELResolver</el-resolver>
+ * </application>
+ * + * @author Juergen Hoeller + * @since 2.5 + * @see SpringBeanFacesELResolver + * @see org.springframework.web.jsf.FacesContextUtils#getWebApplicationContext + */ +public class WebApplicationContextFacesELResolver extends ELResolver { + + /** + * Name of the exposed WebApplicationContext variable: "webApplicationContext". + */ + public static final String WEB_APPLICATION_CONTEXT_VARIABLE_NAME = "webApplicationContext"; + + + /** Logger available to subclasses */ + protected final Log logger = LogFactory.getLog(getClass()); + + + public Object getValue(ELContext elContext, Object base, Object property) throws ELException { + if (base != null) { + if (base instanceof WebApplicationContext) { + WebApplicationContext wac = (WebApplicationContext) base; + String beanName = property.toString(); + if (logger.isTraceEnabled()) { + logger.trace("Attempting to resolve property '" + beanName + "' in root WebApplicationContext"); + } + if (wac.containsBean(beanName)) { + if (logger.isDebugEnabled()) { + logger.debug("Successfully resolved property '" + beanName + "' in root WebApplicationContext"); + } + elContext.setPropertyResolved(true); + try { + return wac.getBean(beanName); + } + catch (BeansException ex) { + throw new ELException(ex); + } + } + else { + // Mimic standard JSF/JSP behavior when base is a Map by returning null. + return null; + } + } + } + else { + if (WEB_APPLICATION_CONTEXT_VARIABLE_NAME.equals(property)) { + elContext.setPropertyResolved(true); + return getWebApplicationContext(elContext); + } + } + + return null; + } + + public Class getType(ELContext elContext, Object base, Object property) throws ELException { + if (base != null) { + if (base instanceof WebApplicationContext) { + WebApplicationContext wac = (WebApplicationContext) base; + String beanName = property.toString(); + if (logger.isDebugEnabled()) { + logger.debug("Attempting to resolve property '" + beanName + "' in root WebApplicationContext"); + } + if (wac.containsBean(beanName)) { + if (logger.isDebugEnabled()) { + logger.debug("Successfully resolved property '" + beanName + "' in root WebApplicationContext"); + } + elContext.setPropertyResolved(true); + try { + return wac.getType(beanName); + } + catch (BeansException ex) { + throw new ELException(ex); + } + } + else { + // Mimic standard JSF/JSP behavior when base is a Map by returning null. + return null; + } + } + } + else { + if (WEB_APPLICATION_CONTEXT_VARIABLE_NAME.equals(property)) { + elContext.setPropertyResolved(true); + return WebApplicationContext.class; + } + } + + return null; + } + + public void setValue(ELContext elContext, Object base, Object property, Object value) throws ELException { + } + + public boolean isReadOnly(ELContext elContext, Object base, Object property) throws ELException { + if (base instanceof WebApplicationContext) { + elContext.setPropertyResolved(true); + return false; + } + return false; + } + + public Iterator getFeatureDescriptors(ELContext elContext, Object base) { + return null; + } + + public Class getCommonPropertyType(ELContext elContext, Object base) { + return Object.class; + } + + + /** + * Retrieve the WebApplicationContext reference to expose. + *

The default implementation delegates to FacesContextUtils, + * returning null if no WebApplicationContext found. + * @param elContext the current JSF ELContext + * @return the Spring web application context + * @see org.springframework.web.jsf.FacesContextUtils#getWebApplicationContext + */ + protected WebApplicationContext getWebApplicationContext(ELContext elContext) { + FacesContext facesContext = FacesContext.getCurrentInstance(); + return FacesContextUtils.getRequiredWebApplicationContext(facesContext); + } + +} Index: 3rdParty_sources/spring/org/springframework/web/jsf/el/package.html =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/web/jsf/el/package.html,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/web/jsf/el/package.html 17 Aug 2012 15:16:17 -0000 1.1 @@ -0,0 +1,11 @@ + + + +Support classes for integrating a JSF 1.2 web tier with a Spring middle tier +which is hosted in a Spring root WebApplicationContext. + +

Supports JSF 1.2's ELResolver mechanism, providing closer integration +than JSF 1.1's VariableResolver mechanism allowed for. + + + Index: 3rdParty_sources/spring/org/springframework/web/util/CookieGenerator.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/web/util/CookieGenerator.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/web/util/CookieGenerator.java 17 Aug 2012 15:16:09 -0000 1.1 @@ -0,0 +1,204 @@ +/* + * 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.web.util; + +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServletResponse; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * Helper class for cookie generation, carrying cookie descriptor settings + * as bean properties and being able to add and remove cookie to/from a + * given response. + * + *

Can serve as base class for components that generate specific cookies, + * like CookieLocaleResolcer and CookieThemeResolver. + * + * @author Juergen Hoeller + * @since 1.1.4 + * @see #addCookie + * @see #removeCookie + * @see org.springframework.web.servlet.i18n.CookieLocaleResolver + * @see org.springframework.web.servlet.theme.CookieThemeResolver + */ +public class CookieGenerator { + + /** + * Default path that cookies will be visible to: "/", i.e. the entire server. + */ + public static final String DEFAULT_COOKIE_PATH = "/"; + + /** + * Default maximum age of cookies: maximum integer value, i.e. forever. + */ + public static final int DEFAULT_COOKIE_MAX_AGE = Integer.MAX_VALUE; + + + protected final Log logger = LogFactory.getLog(getClass()); + + private String cookieName; + + private String cookieDomain; + + private String cookiePath = DEFAULT_COOKIE_PATH; + + private int cookieMaxAge = DEFAULT_COOKIE_MAX_AGE; + + private boolean cookieSecure = false; + + + /** + * Use the given name for cookies created by this generator. + */ + public void setCookieName(String cookieName) { + this.cookieName = cookieName; + } + + /** + * Return the given name for cookies created by this generator. + */ + public String getCookieName() { + return cookieName; + } + + /** + * Use the given domain for cookies created by this generator. + * The cookie is only visible to servers in this domain. + */ + public void setCookieDomain(String cookieDomain) { + this.cookieDomain = cookieDomain; + } + + /** + * Return the domain for cookies created by this generator, if any. + */ + public String getCookieDomain() { + return cookieDomain; + } + + /** + * Use the given path for cookies created by this generator. + * The cookie is only visible to URLs in this path and below. + */ + public void setCookiePath(String cookiePath) { + this.cookiePath = cookiePath; + } + + /** + * Return the path for cookies created by this generator. + */ + public String getCookiePath() { + return cookiePath; + } + + /** + * Use the given maximum age (in seconds) for cookies created by this generator. + * Useful special value: -1 ... not persistent, deleted when client shuts down + */ + public void setCookieMaxAge(int cookieMaxAge) { + this.cookieMaxAge = cookieMaxAge; + } + + /** + * Return the maximum age for cookies created by this generator. + */ + public int getCookieMaxAge() { + return cookieMaxAge; + } + + /** + * Set whether the cookie should only be sent using a secure protocol, + * such as HTTPS (SSL). This is an indication to the receiving browser, + * not processed by the HTTP server itself. Default is "false". + */ + public void setCookieSecure(boolean cookieSecure) { + this.cookieSecure = cookieSecure; + } + + /** + * Return whether the cookie should only be sent using a secure protocol, + * such as HTTPS (SSL). + */ + public boolean isCookieSecure() { + return cookieSecure; + } + + + /** + * Add a cookie with the given value to the response, + * using the cookie descriptor settings of this generator. + *

Delegates to createCookie for cookie creation. + * @param response the HTTP response to add the cookie to + * @param cookieValue the value of the cookie to add + * @see #setCookieName + * @see #setCookieDomain + * @see #setCookiePath + * @see #setCookieMaxAge + * @see #createCookie + */ + public void addCookie(HttpServletResponse response, String cookieValue) { + Cookie cookie = createCookie(cookieValue); + cookie.setMaxAge(getCookieMaxAge()); + if (isCookieSecure()) { + cookie.setSecure(true); + } + response.addCookie(cookie); + if (logger.isDebugEnabled()) { + logger.debug("Added cookie with name [" + getCookieName() + "] and value [" + cookieValue + "]"); + } + } + + /** + * Remove the cookie that this generator describes from the response. + * Will generate a cookie with empty value and max age 0. + *

Delegates to createCookie for cookie creation. + * @param response the HTTP response to remove the cookie from + * @see #setCookieName + * @see #setCookieDomain + * @see #setCookiePath + * @see #createCookie + */ + public void removeCookie(HttpServletResponse response) { + Cookie cookie = createCookie(""); + cookie.setMaxAge(0); + response.addCookie(cookie); + if (logger.isDebugEnabled()) { + logger.debug("Removed cookie with name [" + getCookieName() + "]"); + } + } + + /** + * Create a cookie with the given value, using the cookie descriptor + * settings of this generator (except for "cookieMaxAge"). + * @param cookieValue the value of the cookie to crate + * @return the cookie + * @see #setCookieName + * @see #setCookieDomain + * @see #setCookiePath + */ + protected Cookie createCookie(String cookieValue) { + Cookie cookie = new Cookie(getCookieName(), cookieValue); + if (getCookieDomain() != null) { + cookie.setDomain(getCookieDomain()); + } + cookie.setPath(getCookiePath()); + return cookie; + } + +} Index: 3rdParty_sources/spring/org/springframework/web/util/ExpressionEvaluationUtils.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/web/util/ExpressionEvaluationUtils.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/web/util/ExpressionEvaluationUtils.java 17 Aug 2012 15:16:09 -0000 1.1 @@ -0,0 +1,456 @@ +/* + * 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.web.util; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import javax.servlet.ServletContext; +import javax.servlet.jsp.JspException; +import javax.servlet.jsp.PageContext; +import javax.servlet.jsp.el.ELException; +import javax.servlet.jsp.el.Expression; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.taglibs.standard.lang.support.ExpressionEvaluatorManager; + +import org.springframework.util.Assert; +import org.springframework.util.ClassUtils; + +/** + * Convenience methods for transparent access to JSP 2.0's built-in + * {@link javax.servlet.jsp.el.ExpressionEvaluator} or the standalone + * {@link org.apache.taglibs.standard.lang.support.ExpressionEvaluatorManager} + * of Jakarta's JSTL implementation. + * + *

Automatically detects JSP 2.0 or Jakarta JSTL, preferring the JSP 2.0 + * mechanism if available. Also detects the JSP 2.0 API being present but + * the runtime JSP engine not actually supporting JSP 2.0, falling back to + * the Jakarta JSTL in this case. Throws an exception when encountering actual + * EL expressions if neither JSP 2.0 nor the Jakarta JSTL is available. + * + *

In the case of JSP 2.0, this class will by default use standard + * evaluate calls. If your application server happens to be + * inefficient in that respect, consider setting Spring's "cacheJspExpressions" + * context-param in web.xml to "true", which will use + * parseExpression calls with cached Expression objects instead. + * + *

The evaluation methods check if the value contains "${" before + * invoking the EL evaluator, treating the value as "normal" expression + * (i.e. a literal String value) else. + * + *

Note: The evaluation methods do not have a runtime dependency on + * JSP 2.0 or on Jakarta's JSTL implementation, as long as they are not + * asked to process actual EL expressions. This allows for using EL-aware + * tags with Java-based JSP expressions instead, for example. + * + * @author Juergen Hoeller + * @author Alef Arendsen + * @since 11.07.2003 + * @see javax.servlet.jsp.el.ExpressionEvaluator#evaluate + * @see javax.servlet.jsp.el.ExpressionEvaluator#parseExpression + * @see org.apache.taglibs.standard.lang.support.ExpressionEvaluatorManager + */ +public abstract class ExpressionEvaluationUtils { + + /** + * JSP 2.0 expression cache parameter at the servlet context level + * (i.e. a context-param in web.xml): "cacheJspExpressions". + */ + public static final String EXPRESSION_CACHE_CONTEXT_PARAM = "cacheJspExpressions"; + + public static final String EXPRESSION_PREFIX = "${"; + + public static final String EXPRESSION_SUFFIX = "}"; + + + private static final String EXPRESSION_CACHE_FLAG_CONTEXT_ATTR = + ExpressionEvaluationUtils.class.getName() + ".CACHE_JSP_EXPRESSIONS"; + + private static final String EXPRESSION_CACHE_MAP_CONTEXT_ATTR = + ExpressionEvaluationUtils.class.getName() + ".JSP_EXPRESSION_CACHE"; + + private static final String JSP_20_CLASS_NAME = + "javax.servlet.jsp.el.ExpressionEvaluator"; + + private static final String JAKARTA_JSTL_CLASS_NAME = + "org.apache.taglibs.standard.lang.support.ExpressionEvaluatorManager"; + + + private static final Log logger = LogFactory.getLog(ExpressionEvaluationUtils.class); + + private static ExpressionEvaluationHelper helper; + + + static { + ClassLoader cl = ExpressionEvaluationUtils.class.getClassLoader(); + if (ClassUtils.isPresent(JSP_20_CLASS_NAME, cl)) { + logger.debug("Found JSP 2.0 ExpressionEvaluator"); + if (ClassUtils.isPresent(JAKARTA_JSTL_CLASS_NAME, cl)) { + logger.debug("Found Jakarta JSTL ExpressionEvaluatorManager"); + helper = new Jsp20ExpressionEvaluationHelper(new JakartaExpressionEvaluationHelper()); + } + else { + helper = new Jsp20ExpressionEvaluationHelper(new NoExpressionEvaluationHelper()); + } + } + else if (ClassUtils.isPresent(JAKARTA_JSTL_CLASS_NAME, cl)) { + logger.debug("Found Jakarta JSTL ExpressionEvaluatorManager"); + helper = new JakartaExpressionEvaluationHelper(); + } + else { + logger.debug("JSP expression evaluation not available"); + helper = new NoExpressionEvaluationHelper(); + } + } + + + /** + * Check if the given expression value is an EL expression. + * @param value the expression to check + * @return true if the expression is an EL expression, + * false otherwise + */ + public static boolean isExpressionLanguage(String value) { + return (value != null && value.indexOf(EXPRESSION_PREFIX) != -1); + } + + /** + * Evaluate the given expression (be it EL or a literal String value) + * to an Object of a given type, + * @param attrName name of the attribute (typically a JSP tag attribute) + * @param attrValue value of the attribute + * @param resultClass class that the result should have (String, Integer, Boolean) + * @param pageContext current JSP PageContext + * @return the result of the evaluation + * @throws JspException in case of parsing errors, also in case of type mismatch + * if the passed-in literal value is not an EL expression and not assignable to + * the result class + */ + public static Object evaluate(String attrName, String attrValue, Class resultClass, PageContext pageContext) + throws JspException { + + if (isExpressionLanguage(attrValue)) { + return doEvaluate(attrName, attrValue, resultClass, pageContext); + } + else if (attrValue != null && resultClass != null && !resultClass.isInstance(attrValue)) { + throw new JspException("Attribute value \"" + attrValue + "\" is neither a JSP EL expression nor " + + "assignable to result class [" + resultClass.getName() + "]"); + } + else { + return attrValue; + } + } + + /** + * Evaluate the given expression (be it EL or a literal String value) to an Object. + * @param attrName name of the attribute (typically a JSP tag attribute) + * @param attrValue value of the attribute + * @param pageContext current JSP PageContext + * @return the result of the evaluation + * @throws JspException in case of parsing errors + */ + public static Object evaluate(String attrName, String attrValue, PageContext pageContext) + throws JspException { + + if (isExpressionLanguage(attrValue)) { + return doEvaluate(attrName, attrValue, Object.class, pageContext); + } + else { + return attrValue; + } + } + + /** + * Evaluate the given expression (be it EL or a literal String value) to a String. + * @param attrName name of the attribute (typically a JSP tag attribute) + * @param attrValue value of the attribute + * @param pageContext current JSP PageContext + * @return the result of the evaluation + * @throws JspException in case of parsing errors + */ + public static String evaluateString(String attrName, String attrValue, PageContext pageContext) + throws JspException { + + if (isExpressionLanguage(attrValue)) { + return (String) doEvaluate(attrName, attrValue, String.class, pageContext); + } + else { + return attrValue; + } + } + + /** + * Evaluate the given expression (be it EL or a literal String value) to an integer. + * @param attrName name of the attribute (typically a JSP tag attribute) + * @param attrValue value of the attribute + * @param pageContext current JSP PageContext + * @return the result of the evaluation + * @throws JspException in case of parsing errors + */ + public static int evaluateInteger(String attrName, String attrValue, PageContext pageContext) + throws JspException { + + if (isExpressionLanguage(attrValue)) { + return ((Integer) doEvaluate(attrName, attrValue, Integer.class, pageContext)).intValue(); + } + else { + return Integer.parseInt(attrValue); + } + } + + /** + * Evaluate the given expression (be it EL or a literal String value) to a boolean. + * @param attrName name of the attribute (typically a JSP tag attribute) + * @param attrValue value of the attribute + * @param pageContext current JSP PageContext + * @return the result of the evaluation + * @throws JspException in case of parsing errors + */ + public static boolean evaluateBoolean(String attrName, String attrValue, PageContext pageContext) + throws JspException { + + if (isExpressionLanguage(attrValue)) { + return ((Boolean) doEvaluate(attrName, attrValue, Boolean.class, pageContext)).booleanValue(); + } + else { + return Boolean.valueOf(attrValue).booleanValue(); + } + } + + + /** + * Actually evaluate the given expression (be it EL or a literal String value) + * to an Object of a given type. Supports concatenated expressions, + * for example: "${var1}text${var2}" + * @param attrName name of the attribute + * @param attrValue value of the attribute + * @param resultClass class that the result should have + * @param pageContext current JSP PageContext + * @return the result of the evaluation + * @throws JspException in case of parsing errors + */ + private static Object doEvaluate(String attrName, String attrValue, Class resultClass, PageContext pageContext) + throws JspException { + + Assert.notNull(attrValue, "Attribute value must not be null"); + Assert.notNull(resultClass, "Result class must not be null"); + Assert.notNull(pageContext, "PageContext must not be null"); + + if (resultClass.isAssignableFrom(String.class)) { + StringBuffer resultValue = null; + int exprPrefixIndex = -1; + int exprSuffixIndex = 0; + do { + exprPrefixIndex = attrValue.indexOf(EXPRESSION_PREFIX, exprSuffixIndex); + if (exprPrefixIndex != -1) { + int prevExprSuffixIndex = exprSuffixIndex; + exprSuffixIndex = attrValue.indexOf(EXPRESSION_SUFFIX, exprPrefixIndex + EXPRESSION_PREFIX.length()); + String expr = null; + if (exprSuffixIndex != -1) { + exprSuffixIndex += EXPRESSION_SUFFIX.length(); + expr = attrValue.substring(exprPrefixIndex, exprSuffixIndex); + } + else { + expr = attrValue.substring(exprPrefixIndex); + } + if (expr.length() == attrValue.length()) { + // A single expression without static prefix or suffix -> + // parse it with the specified result class rather than String. + return helper.evaluate(attrName, attrValue, resultClass, pageContext); + } + else { + // We actually need to concatenate partial expressions into a String. + if (resultValue == null) { + resultValue = new StringBuffer(); + } + resultValue.append(attrValue.substring(prevExprSuffixIndex, exprPrefixIndex)); + resultValue.append(helper.evaluate(attrName, expr, String.class, pageContext)); + } + } + else { + if (resultValue == null) { + resultValue = new StringBuffer(); + } + resultValue.append(attrValue.substring(exprSuffixIndex)); + } + } + while (exprPrefixIndex != -1 && exprSuffixIndex != -1); + return resultValue.toString(); + } + + else { + return helper.evaluate(attrName, attrValue, resultClass, pageContext); + } + } + + /** + * Determine whether JSP 2.0 expressions are supposed to be cached + * and return the corresponding cache Map, or null if + * caching is not enabled. + * @param pageContext current JSP PageContext + * @return the cache Map, or null if caching is disabled + */ + private static Map getJspExpressionCache(PageContext pageContext) { + ServletContext servletContext = pageContext.getServletContext(); + Map cacheMap = (Map) servletContext.getAttribute(EXPRESSION_CACHE_MAP_CONTEXT_ATTR); + if (cacheMap == null) { + Boolean cacheFlag = (Boolean) servletContext.getAttribute(EXPRESSION_CACHE_FLAG_CONTEXT_ATTR); + if (cacheFlag == null) { + cacheFlag = Boolean.valueOf(servletContext.getInitParameter(EXPRESSION_CACHE_CONTEXT_PARAM)); + servletContext.setAttribute(EXPRESSION_CACHE_FLAG_CONTEXT_ATTR, cacheFlag); + } + if (cacheFlag.booleanValue()) { + cacheMap = Collections.synchronizedMap(new HashMap()); + servletContext.setAttribute(EXPRESSION_CACHE_MAP_CONTEXT_ATTR, cacheMap); + } + } + return cacheMap; + } + + + /** + * Internal interface for evaluating a JSP EL expression. + */ + private static interface ExpressionEvaluationHelper { + + public Object evaluate(String attrName, String attrValue, Class resultClass, PageContext pageContext) + throws JspException; + } + + + /** + * Fallback ExpressionEvaluationHelper: + * always throws an exception in case of an actual EL expression. + */ + private static class NoExpressionEvaluationHelper implements ExpressionEvaluationHelper { + + public Object evaluate(String attrName, String attrValue, Class resultClass, PageContext pageContext) + throws JspException { + + throw new JspException( + "Neither JSP 2.0 nor Jakarta JSTL available - cannot parse JSP EL expression \"" + attrValue + "\""); + } + } + + + /** + * Actual invocation of the Jakarta ExpressionEvaluatorManager. + * In separate inner class to avoid runtime dependency on Jakarta's + * JSTL implementation, for evaluation of non-EL expressions. + */ + private static class JakartaExpressionEvaluationHelper implements ExpressionEvaluationHelper { + + public Object evaluate(String attrName, String attrValue, Class resultClass, PageContext pageContext) + throws JspException { + + return ExpressionEvaluatorManager.evaluate(attrName, attrValue, resultClass, pageContext); + } + } + + + /** + * Actual invocation of the JSP 2.0 ExpressionEvaluator. + * In separate inner class to avoid runtime dependency on JSP 2.0, + * for evaluation of non-EL expressions. + */ + private static class Jsp20ExpressionEvaluationHelper implements ExpressionEvaluationHelper { + + private final ExpressionEvaluationHelper fallback; + + private boolean fallbackNecessary = false; + + public Jsp20ExpressionEvaluationHelper(ExpressionEvaluationHelper fallback) { + this.fallback = fallback; + } + + public Object evaluate(String attrName, String attrValue, Class resultClass, PageContext pageContext) + throws JspException { + + if (isFallbackNecessary()) { + return this.fallback.evaluate(attrName, attrValue, resultClass, pageContext); + } + + try { + Map expressionCache = getJspExpressionCache(pageContext); + if (expressionCache != null) { + // We are supposed to explicitly create and cache JSP Expression objects. + ExpressionCacheKey cacheKey = new ExpressionCacheKey(attrValue, resultClass); + Expression expr = (Expression) expressionCache.get(cacheKey); + if (expr == null) { + expr = pageContext.getExpressionEvaluator().parseExpression(attrValue, resultClass, null); + expressionCache.put(cacheKey, expr); + } + return expr.evaluate(pageContext.getVariableResolver()); + } + else { + // We're simply calling the JSP 2.0 evaluate method straight away. + return pageContext.getExpressionEvaluator().evaluate( + attrValue, resultClass, pageContext.getVariableResolver(), null); + } + } + catch (ELException ex) { + throw new JspException("Parsing of JSP EL expression \"" + attrValue + "\" failed", ex); + } + catch (LinkageError err) { + logger.debug("JSP 2.0 ExpressionEvaluator API present but not implemented - using fallback", err); + setFallbackNecessary(); + return this.fallback.evaluate(attrName, attrValue, resultClass, pageContext); + } + } + + private synchronized boolean isFallbackNecessary() { + return this.fallbackNecessary; + } + + private synchronized void setFallbackNecessary() { + this.fallbackNecessary = true; + } + } + + + /** + * Cache key class for JSP 2.0 Expression objects. + */ + private static class ExpressionCacheKey { + + private final String value; + private final Class resultClass; + private final int hashCode; + + public ExpressionCacheKey(String value, Class resultClass) { + this.value = value; + this.resultClass = resultClass; + this.hashCode = this.value.hashCode() * 29 + this.resultClass.hashCode(); + } + + public boolean equals(Object obj) { + if (!(obj instanceof ExpressionCacheKey)) { + return false; + } + ExpressionCacheKey other = (ExpressionCacheKey) obj; + return (this.value.equals(other.value) && this.resultClass.equals(other.resultClass)); + } + + public int hashCode() { + return this.hashCode; + } + } + +} Index: 3rdParty_sources/spring/org/springframework/web/util/HtmlCharacterEntityDecoder.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/web/util/HtmlCharacterEntityDecoder.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/web/util/HtmlCharacterEntityDecoder.java 17 Aug 2012 15:16:09 -0000 1.1 @@ -0,0 +1,153 @@ +/* + * 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.web.util; + +/** + * Helper for decoding HTML Strings by replacing character + * entity references with the referred character. + * + * @author Juergen Hoeller + * @author Martin Kersten + * @since 1.2.1 + */ +class HtmlCharacterEntityDecoder { + + private static final int MAX_REFERENCE_SIZE = 10; + + + private final HtmlCharacterEntityReferences characterEntityReferences; + + private final String originalMessage; + + private final StringBuffer decodedMessage; + + private int currentPosition = 0; + + private int nextPotentialReferencePosition = -1; + + private int nextSemicolonPosition = -2; + + + public HtmlCharacterEntityDecoder(HtmlCharacterEntityReferences characterEntityReferences, String original) { + this.characterEntityReferences = characterEntityReferences; + this.originalMessage = original; + this.decodedMessage = new StringBuffer(originalMessage.length()); + } + + public String decode() { + while (currentPosition < originalMessage.length()) { + findNextPotentialReference(currentPosition); + copyCharactersTillPotentialReference(); + processPossibleReference(); + } + return decodedMessage.toString(); + } + + private void findNextPotentialReference(int startPosition) { + nextPotentialReferencePosition = Math.max(startPosition, nextSemicolonPosition - MAX_REFERENCE_SIZE); + + do { + nextPotentialReferencePosition = + originalMessage.indexOf('&', nextPotentialReferencePosition); + + if (nextSemicolonPosition != -1 && + nextSemicolonPosition < nextPotentialReferencePosition) + nextSemicolonPosition = originalMessage.indexOf(';', nextPotentialReferencePosition + 1); + + boolean isPotentialReference = + nextPotentialReferencePosition != -1 + && nextSemicolonPosition != -1 + && nextPotentialReferencePosition - nextSemicolonPosition < MAX_REFERENCE_SIZE; + + if (isPotentialReference) { + break; + } + if (nextPotentialReferencePosition == -1) { + break; + } + if (nextSemicolonPosition == -1) { + nextPotentialReferencePosition = -1; + break; + } + + nextPotentialReferencePosition = nextPotentialReferencePosition + 1; + } + while (nextPotentialReferencePosition != -1); + } + + + private void copyCharactersTillPotentialReference() { + if (nextPotentialReferencePosition != currentPosition) { + int skipUntilIndex = nextPotentialReferencePosition != -1 ? + nextPotentialReferencePosition : originalMessage.length(); + if (skipUntilIndex - currentPosition > 3) { + decodedMessage.append(originalMessage.substring(currentPosition, skipUntilIndex)); + currentPosition = skipUntilIndex; + } + else { + while (currentPosition < skipUntilIndex) + decodedMessage.append(originalMessage.charAt(currentPosition++)); + } + } + } + + private void processPossibleReference() { + if (nextPotentialReferencePosition != -1) { + boolean isNumberedReference = originalMessage.charAt(currentPosition + 1) == '#'; + boolean wasProcessable = isNumberedReference ? processNumberedReference() : processNamedReference(); + if (wasProcessable) { + currentPosition = nextSemicolonPosition + 1; + } + else { + char currentChar = originalMessage.charAt(currentPosition); + decodedMessage.append(currentChar); + currentPosition++; + } + } + } + + private boolean processNumberedReference() { + boolean isHexNumberedReference = + originalMessage.charAt(nextPotentialReferencePosition + 2) == 'x' || + originalMessage.charAt(nextPotentialReferencePosition + 2) == 'X'; + try { + int value = (!isHexNumberedReference) ? + Integer.parseInt(getReferenceSubstring(2)) : + Integer.parseInt(getReferenceSubstring(3), 16); + decodedMessage.append((char) value); + return true; + } + catch (NumberFormatException ex) { + return false; + } + } + + private boolean processNamedReference() { + String referenceName = getReferenceSubstring(1); + char mappedCharacter = characterEntityReferences.convertToCharacter(referenceName); + if (mappedCharacter != HtmlCharacterEntityReferences.CHAR_NULL) { + decodedMessage.append(mappedCharacter); + return true; + } + return false; + } + + private String getReferenceSubstring(int referenceOffset) { + return originalMessage.substring(nextPotentialReferencePosition + referenceOffset, nextSemicolonPosition); + } + +} Index: 3rdParty_sources/spring/org/springframework/web/util/HtmlCharacterEntityReferences.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/web/util/HtmlCharacterEntityReferences.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/web/util/HtmlCharacterEntityReferences.java 17 Aug 2012 15:16:09 -0000 1.1 @@ -0,0 +1,138 @@ +/* + * 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.web.util; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; + +import org.springframework.util.Assert; + +/** + * Represents a set of character entity references defined by the + * HTML 4.0 standard. + * + *

A complete description of the HTML 4.0 character set can be found + * at http://www.w3.org/TR/html4/charset.html. + * + * @author Juergen Hoeller + * @author Martin Kersten + * @since 1.2.1 + */ +class HtmlCharacterEntityReferences { + + static final char REFERENCE_START = '&'; + + static final String DECIMAL_REFERENCE_START = "&#"; + + static final String HEX_REFERENCE_START = "&#x"; + + static final char REFERENCE_END = ';'; + + static final char CHAR_NULL = (char) -1; + + + private static final String PROPERTIES_FILE = "HtmlCharacterEntityReferences.properties"; + + + private final String[] characterToEntityReferenceMap = new String[3000]; + + private final Map entityReferenceToCharacterMap = new HashMap(252); + + + /** + * Returns a new set of character entity references reflecting the HTML 4.0 character set. + */ + public HtmlCharacterEntityReferences() { + Properties entityReferences = new Properties(); + + // Load refeence definition file. + InputStream is = HtmlCharacterEntityReferences.class.getResourceAsStream(PROPERTIES_FILE); + if (is == null) { + throw new IllegalStateException( + "Cannot find reference definition file [HtmlCharacterEntityReferences.properties] as class path resource"); + } + try { + try { + entityReferences.load(is); + } + finally { + is.close(); + } + } + catch (IOException ex) { + throw new IllegalStateException( + "Failed to parse reference definition file [HtmlCharacterEntityReferences.properties]: " + ex.getMessage()); + } + + // Parse reference definition properites. + Enumeration keys = entityReferences.propertyNames(); + while (keys.hasMoreElements()) { + String key = (String) keys.nextElement(); + int referredChar = Integer.parseInt(key); + Assert.isTrue((referredChar < 1000 || (referredChar >= 8000 && referredChar < 10000)), + "Invalid reference to special HTML entity: " + referredChar); + int index = (referredChar < 1000 ? referredChar : referredChar - 7000); + String reference = entityReferences.getProperty(key); + this.characterToEntityReferenceMap[index] = REFERENCE_START + reference + REFERENCE_END; + this.entityReferenceToCharacterMap.put(reference, new Character((char) referredChar)); + } + } + + /** + * Return the number of supported entity references. + */ + public int getSupportedReferenceCount() { + return this.entityReferenceToCharacterMap.size(); + } + + /** + * Return true if the given character is mapped to a supported entity reference. + */ + public boolean isMappedToReference(char character) { + return (convertToReference(character) != null); + } + + /** + * Return the reference mapped to the given character or null. + */ + public String convertToReference(char character) { + if (character < 1000 || (character >= 8000 && character < 10000)) { + int index = (character < 1000 ? character : character - 7000); + String entityReference = this.characterToEntityReferenceMap[index]; + if (entityReference != null) { + return entityReference; + } + } + return null; + } + + /** + * Return the char mapped to the given entityReference or -1. + */ + public char convertToCharacter(String entityReference) { + Character referredCharacter = (Character) this.entityReferenceToCharacterMap.get(entityReference); + if (referredCharacter != null) { + return referredCharacter.charValue(); + } + return CHAR_NULL; + } + +} Index: 3rdParty_sources/spring/org/springframework/web/util/HtmlCharacterEntityReferences.properties =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/web/util/HtmlCharacterEntityReferences.properties,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/web/util/HtmlCharacterEntityReferences.properties 17 Aug 2012 15:16:09 -0000 1.1 @@ -0,0 +1,268 @@ +# Character Entity References defined by the HTML 4.0 standard. +# A complete description of the HTML 4.0 character set can be found at: +# http://www.w3.org/TR/html4/charset.html + + +# Character entity references for ISO 8859-1 characters + +160 = nbsp +161 = iexcl +162 = cent +163 = pound +164 = curren +165 = yen +166 = brvbar +167 = sect +168 = uml +169 = copy +170 = ordf +171 = laquo +172 = not +173 = shy +174 = reg +175 = macr +176 = deg +177 = plusmn +178 = sup2 +179 = sup3 +180 = acute +181 = micro +182 = para +183 = middot +184 = cedil +185 = sup1 +186 = ordm +187 = raquo +188 = frac14 +189 = frac12 +190 = frac34 +191 = iquest +192 = Agrave +193 = Aacute +194 = Acirc +195 = Atilde +196 = Auml +197 = Aring +198 = AElig +199 = Ccedil +200 = Egrave +201 = Eacute +202 = Ecirc +203 = Euml +204 = Igrave +205 = Iacute +206 = Icirc +207 = Iuml +208 = ETH +209 = Ntilde +210 = Ograve +211 = Oacute +212 = Ocirc +213 = Otilde +214 = Ouml +215 = times +216 = Oslash +217 = Ugrave +218 = Uacute +219 = Ucirc +220 = Uuml +221 = Yacute +222 = THORN +223 = szlig +224 = agrave +225 = aacute +226 = acirc +227 = atilde +228 = auml +229 = aring +230 = aelig +231 = ccedil +232 = egrave +233 = eacute +234 = ecirc +235 = euml +236 = igrave +237 = iacute +238 = icirc +239 = iuml +240 = eth +241 = ntilde +242 = ograve +243 = oacute +244 = ocirc +245 = otilde +246 = ouml +247 = divide +248 = oslash +249 = ugrave +250 = uacute +251 = ucirc +252 = uuml +253 = yacute +254 = thorn +255 = yuml + + +# Character entity references for symbols, mathematical symbols, and Greek letters + +402 = fnof +913 = Alpha +914 = Beta +915 = Gamma +916 = Delta +917 = Epsilon +918 = Zeta +919 = Eta +920 = Theta +921 = Iota +922 = Kappa +923 = Lambda +924 = Mu +925 = Nu +926 = Xi +927 = Omicron +928 = Pi +929 = Rho +931 = Sigma +932 = Tau +933 = Upsilon +934 = Phi +935 = Chi +936 = Psi +937 = Omega +945 = alpha +946 = beta +947 = gamma +948 = delta +949 = epsilon +950 = zeta +951 = eta +952 = theta +953 = iota +954 = kappa +955 = lambda +956 = mu +957 = nu +958 = xi +959 = omicron +960 = pi +961 = rho +962 = sigmaf +963 = sigma +964 = tau +965 = upsilon +966 = phi +967 = chi +968 = psi +969 = omega +977 = thetasym +978 = upsih +982 = piv +8226 = bull +8230 = hellip +8242 = prime +8243 = Prime +8254 = oline +8260 = frasl +8472 = weierp +8465 = image +8476 = real +8482 = trade +8501 = alefsym +8592 = larr +8593 = uarr +8594 = rarr +8595 = darr +8596 = harr +8629 = crarr +8656 = lArr +8657 = uArr +8658 = rArr +8659 = dArr +8660 = hArr +8704 = forall +8706 = part +8707 = exist +8709 = empty +8711 = nabla +8712 = isin +8713 = notin +8715 = ni +8719 = prod +8721 = sum +8722 = minus +8727 = lowast +8730 = radic +8733 = prop +8734 = infin +8736 = ang +8743 = and +8744 = or +8745 = cap +8746 = cup +8747 = int +8756 = there4 +8764 = sim +8773 = cong +8776 = asymp +8800 = ne +8801 = equiv +8804 = le +8805 = ge +8834 = sub +8835 = sup +8836 = nsub +8838 = sube +8839 = supe +8853 = oplus +8855 = otimes +8869 = perp +8901 = sdot +8968 = lceil +8969 = rceil +8970 = lfloor +8971 = rfloor +9001 = lang +9002 = rang +9674 = loz +9824 = spades +9827 = clubs +9829 = hearts +9830 = diams + + +# Character entity references for markup-significant and internationalization characters + +34 = quot +38 = amp +60 = lt +62 = gt +338 = OElig +339 = oelig +352 = Scaron +353 = scaron +376 = Yuml +710 = circ +732 = tilde +8194 = ensp +8195 = emsp +8201 = thinsp +8204 = zwnj +8205 = zwj +8206 = lrm +8207 = rlm +8211 = ndash +8212 = mdash +8216 = lsquo +8217 = rsquo +8218 = sbquo +8220 = ldquo +8221 = rdquo +8222 = bdquo +8224 = dagger +8225 = Dagger +8240 = permil +8249 = lsaquo +8250 = rsaquo +8364 = euro + Index: 3rdParty_sources/spring/org/springframework/web/util/HtmlUtils.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/web/util/HtmlUtils.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/web/util/HtmlUtils.java 17 Aug 2012 15:16:09 -0000 1.1 @@ -0,0 +1,165 @@ +/* + * 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.web.util; + +/** + * Utility class for HTML escaping. Escapes and unescapes + * based on the W3C HTML 4.01 recommendation, handling + * character entity references. + * + *

Reference: + * http://www.w3.org/TR/html4/charset.html + * + *

For a comprehensive set of String escaping utilities, + * consider Jakarta Commons Lang and its StringEscapeUtils class. + * We are not using that class here to avoid a runtime dependency + * on Commons Lang just for HTML escaping. Furthermore, Spring's + * HTML escaping is more flexible and 100% HTML 4.0 compliant. + * + * @author Juergen Hoeller + * @author Martin Kersten + * @since 01.03.2003 + * @see org.apache.commons.lang.StringEscapeUtils + */ +public abstract class HtmlUtils { + + /** + * Shared instance of pre-parsed HTML character entity references. + */ + private static final HtmlCharacterEntityReferences characterEntityReferences = + new HtmlCharacterEntityReferences(); + + + /** + * Turn special characters into HTML character references. + * Handles complete character set defined in HTML 4.01 recommendation. + *

Escapes all special characters to their corresponding + * entity reference (e.g. <). + *

Reference: + * + * http://www.w3.org/TR/html4/sgml/entities.html + * + * @param input the (unescaped) input string + * @return the escaped string + */ + public static String htmlEscape(String input) { + if (input == null) { + return null; + } + StringBuffer escaped = new StringBuffer(input.length() * 2); + for (int i = 0; i < input.length(); i++) { + char character = input.charAt(i); + String reference = characterEntityReferences.convertToReference(character); + if (reference != null) { + escaped.append(reference); + } + else { + escaped.append(character); + } + } + return escaped.toString(); + } + + /** + * Turn special characters into HTML character references. + * Handles complete character set defined in HTML 4.01 recommendation. + *

Escapes all special characters to their corresponding numeric + * reference in decimal format (&#Decimal;). + *

Reference: + * + * http://www.w3.org/TR/html4/sgml/entities.html + * + * @param input the (unescaped) input string + * @return the escaped string + */ + public static String htmlEscapeDecimal(String input) { + if (input == null) { + return null; + } + StringBuffer escaped = new StringBuffer(input.length() * 2); + for (int i = 0; i < input.length(); i++) { + char character = input.charAt(i); + if (characterEntityReferences.isMappedToReference(character)) { + escaped.append(HtmlCharacterEntityReferences.DECIMAL_REFERENCE_START); + escaped.append((int) character); + escaped.append(HtmlCharacterEntityReferences.REFERENCE_END); + } + else { + escaped.append(character); + } + } + return escaped.toString(); + } + + /** + * Turn special characters into HTML character references. + * Handles complete character set defined in HTML 4.01 recommendation. + *

Escapes all special characters to their corresponding numeric + * reference in hex format (&#xHex;). + *

Reference: + * + * http://www.w3.org/TR/html4/sgml/entities.html + * + * @param input the (unescaped) input string + * @return the escaped string + */ + public static String htmlEscapeHex(String input) { + if (input == null) { + return null; + } + StringBuffer escaped = new StringBuffer(input.length() * 2); + for (int i = 0; i < input.length(); i++) { + char character = input.charAt(i); + if (characterEntityReferences.isMappedToReference(character)) { + escaped.append(HtmlCharacterEntityReferences.HEX_REFERENCE_START); + escaped.append(Integer.toString((int) character, 16)); + escaped.append(HtmlCharacterEntityReferences.REFERENCE_END); + } + else { + escaped.append(character); + } + } + return escaped.toString(); + } + + /** + * Turn HTML character references into their plain text UNICODE equivalent. + *

Handles complete character set defined in HTML 4.01 recommendation + * and all reference types (decimal, hex, and entity). + *

Correctly converts the following formats: + *

+ * &#Entity; - (Example: &amp;) case sensitive + * &#Decimal; - (Example: &#68;)
+ * &#xHex; - (Example: &#xE5;) case insensitive
+ *
+ * Gracefully handles malformed character references by copying original + * characters as is when encountered.

+ *

Reference: + * + * http://www.w3.org/TR/html4/sgml/entities.html + * + * @param input the (escaped) input string + * @return the unescaped string + */ + public static String htmlUnescape(String input) { + if (input == null) { + return null; + } + return new HtmlCharacterEntityDecoder(characterEntityReferences, input).decode(); + } + +} Index: 3rdParty_sources/spring/org/springframework/web/util/HttpSessionMutexListener.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/web/util/HttpSessionMutexListener.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/web/util/HttpSessionMutexListener.java 17 Aug 2012 15:16:09 -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.web.util; + +import java.io.Serializable; + +import javax.servlet.http.HttpSessionEvent; +import javax.servlet.http.HttpSessionListener; + +/** + * Servlet 2.3 HttpSessionListener that automatically exposes the + * session mutex when an HttpSession gets created. + * To be registered as a listener in web.xml. + * + *

The session mutex is guaranteed to be the same object during + * the entire lifetime of the session, available under the key defined + * by the SESSION_MUTEX_ATTRIBUTE constant. It serves as a + * safe reference to synchronize on for locking on the current session. + * + *

In many cases, the HttpSession reference itself is a safe mutex + * as well, since it will always be the same object reference for the + * same active logical session. However, this is not guaranteed across + * different servlet containers; the only 100% safe way is a session mutex. + * + * @author Juergen Hoeller + * @since 1.2.7 + * @see WebUtils#SESSION_MUTEX_ATTRIBUTE + * @see WebUtils#getSessionMutex(javax.servlet.http.HttpSession) + * @see org.springframework.web.servlet.mvc.AbstractController#setSynchronizeOnSession + */ +public class HttpSessionMutexListener implements HttpSessionListener { + + public void sessionCreated(HttpSessionEvent event) { + event.getSession().setAttribute(WebUtils.SESSION_MUTEX_ATTRIBUTE, new Mutex()); + } + + public void sessionDestroyed(HttpSessionEvent event) { + event.getSession().removeAttribute(WebUtils.SESSION_MUTEX_ATTRIBUTE); + } + + + /** + * The mutex to be registered. + * Doesn't need to be anything but a plain Object to synchronize on. + * Should be serializable to allow for HttpSession persistence. + */ + private static class Mutex implements Serializable { + } + +} Index: 3rdParty_sources/spring/org/springframework/web/util/IntrospectorCleanupListener.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/web/util/IntrospectorCleanupListener.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/web/util/IntrospectorCleanupListener.java 17 Aug 2012 15:16:09 -0000 1.1 @@ -0,0 +1,83 @@ +/* + * 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.web.util; + +import java.beans.Introspector; + +import javax.servlet.ServletContextEvent; +import javax.servlet.ServletContextListener; + +import org.springframework.beans.CachedIntrospectionResults; + +/** + * Listener that flushes the JDK's {@link java.beans.Introspector JavaBeans Introspector} + * cache on web app shutdown. Register this listener in your web.xml to + * guarantee proper release of the web application class loader and its loaded classes. + * + *

If the JavaBeans Introspector has been used to analyze application classes, + * the system-level Introspector cache will hold a hard reference to those classes. + * Consequently, those classes and the web application class loader will not be + * garbage-collected on web app shutdown! This listener performs proper cleanup, + * to allow for garbage collection to take effect. + * + *

Unfortunately, the only way to clean up the Introspector is to flush + * the entire cache, as there is no way to specifically determine the + * application's classes referenced there. This will remove cached + * introspection results for all other applications in the server too. + * + *

Note that this listener is not necessary when using Spring's beans + * infrastructure within the application, as Spring's own introspection results + * cache will immediately flush an analyzed class from the JavaBeans Introspector + * cache and only hold a cache within the application's own ClassLoader. + * + * Although Spring itself does not create JDK Introspector leaks, note that this + * listener should nevertheless be used in scenarios where the Spring framework classes + * themselves reside in a 'common' ClassLoader (such as the system ClassLoader). + * In such a scenario, this listener will properly clean up Spring's introspection cache. + * + *

Application classes hardly ever need to use the JavaBeans Introspector + * directly, so are normally not the cause of Introspector resource leaks. + * Rather, many libraries and frameworks do not clean up the Introspector: + * e.g. Struts and Quartz. + * + *

Note that a single such Introspector leak will cause the entire web + * app class loader to not get garbage collected! This has the consequence that + * you will see all the application's static class resources (like singletons) + * around after web app shutdown, which is not the fault of those classes! + * + *

This listener should be registered as the first one in web.xml, + * before any application listeners such as Spring's ContextLoaderListener. + * This allows the listener to take full effect at the right time of the lifecycle. + * + * @author Juergen Hoeller + * @since 1.1 + * @see java.beans.Introspector#flushCaches() + * @see org.springframework.beans.CachedIntrospectionResults#acceptClassLoader + * @see org.springframework.beans.CachedIntrospectionResults#clearClassLoader + */ +public class IntrospectorCleanupListener implements ServletContextListener { + + public void contextInitialized(ServletContextEvent event) { + CachedIntrospectionResults.acceptClassLoader(Thread.currentThread().getContextClassLoader()); + } + + public void contextDestroyed(ServletContextEvent event) { + CachedIntrospectionResults.clearClassLoader(Thread.currentThread().getContextClassLoader()); + Introspector.flushCaches(); + } + +} Index: 3rdParty_sources/spring/org/springframework/web/util/JavaScriptUtils.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/web/util/JavaScriptUtils.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/web/util/JavaScriptUtils.java 17 Aug 2012 15:16:09 -0000 1.1 @@ -0,0 +1,85 @@ +/* + * 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.web.util; + +/** + * Utility class for JavaScript escaping. + * Escapes based on the JavaScript 1.5 recommendation. + * + *

Reference: + * + * Core JavaScript 1.5 Guide + * + * + * @author Juergen Hoeller + * @author Rob Harrop + * @since 1.1.1 + */ +public class JavaScriptUtils { + + /** + * Turn special characters into escaped characters conforming to JavaScript. + * Handles complete character set defined in HTML 4.01 recommendation. + * @param input the input string + * @return the escaped string + */ + public static String javaScriptEscape(String input) { + if (input == null) { + return input; + } + + StringBuffer filtered = new StringBuffer(input.length()); + char prevChar = '\u0000'; + char c; + for (int i = 0; i < input.length(); i++) { + c = input.charAt(i); + if (c == '"') { + filtered.append("\\\""); + } + else if (c == '\'') { + filtered.append("\\'"); + } + else if (c == '\\') { + filtered.append("\\\\"); + } + else if (c == '/') { + filtered.append("\\/"); + } + else if (c == '\t') { + filtered.append("\\t"); + } + else if (c == '\n') { + if (prevChar != '\r') { + filtered.append("\\n"); + } + } + else if (c == '\r') { + filtered.append("\\n"); + } + else if (c == '\f') { + filtered.append("\\f"); + } + else { + filtered.append(c); + } + prevChar = c; + + } + return filtered.toString(); + } + +} Index: 3rdParty_sources/spring/org/springframework/web/util/Log4jConfigListener.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/web/util/Log4jConfigListener.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/web/util/Log4jConfigListener.java 17 Aug 2012 15:16:09 -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.web.util; + +import javax.servlet.ServletContextEvent; +import javax.servlet.ServletContextListener; + +/** + * Bootstrap listener for custom log4j initialization in a web environment. + * Delegates to {@link Log4jWebConfigurer} (see its javadoc for configuration details). + * + * WARNING: Assumes an expanded WAR file, both for loading the configuration + * file and for writing the log files. If you want to keep your WAR unexpanded or + * don't need application-specific log files within the WAR directory, don't use + * log4j setup within the application (thus, don't use Log4jConfigListener or + * Log4jConfigServlet). Instead, use a global, VM-wide log4j setup (for example, + * in JBoss) or JDK 1.4's java.util.logging (which is global too). + * + *

This listener should be registered before ContextLoaderListener in web.xml + * when using custom log4j initialization. + * + * @author Juergen Hoeller + * @since 13.03.2003 + * @see Log4jWebConfigurer + * @see Log4jConfigServlet + * @see org.springframework.web.context.ContextLoaderListener + * @see org.springframework.web.context.ContextLoaderServlet + * @see WebAppRootListener + */ +public class Log4jConfigListener implements ServletContextListener { + + public void contextInitialized(ServletContextEvent event) { + Log4jWebConfigurer.initLogging(event.getServletContext()); + } + + public void contextDestroyed(ServletContextEvent event) { + Log4jWebConfigurer.shutdownLogging(event.getServletContext()); + } + +} Index: 3rdParty_sources/spring/org/springframework/web/util/Log4jConfigServlet.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/web/util/Log4jConfigServlet.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/web/util/Log4jConfigServlet.java 17 Aug 2012 15:16:09 -0000 1.1 @@ -0,0 +1,82 @@ +/* + * 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.web.util; + +import java.io.IOException; + +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +/** + * Bootstrap servlet for custom log4j initialization in a web environment. + * Delegates to {@link Log4jWebConfigurer} (see its javadoc for configuration details). + * + * WARNING: Assumes an expanded WAR file, both for loading the configuration + * file and for writing the log files. If you want to keep your WAR unexpanded or + * don't need application-specific log files within the WAR directory, don't use + * log4j setup within the application (thus, don't use Log4jConfigListener or + * Log4jConfigServlet). Instead, use a global, VM-wide log4j setup (for example, + * in JBoss) or JDK 1.4's java.util.logging (which is global too). + * + *

Note: This servlet should have a lower load-on-startup value + * in web.xml than ContextLoaderServlet, when using custom log4j + * initialization. + * + *

Note that this class has been deprecated for containers implementing + * Servlet API 2.4 or higher, in favor of {@link Log4jConfigListener}.
+ * According to Servlet 2.4, listeners must be initialized before load-on-startup + * servlets. Many Servlet 2.3 containers already enforce this behavior + * (see ContextLoaderServlet javadocs for details). If you use such a container, + * this servlet can be replaced with Log4jConfigListener. + * + * @author Juergen Hoeller + * @author Darren Davison + * @since 12.08.2003 + * @see Log4jWebConfigurer + * @see Log4jConfigListener + * @see org.springframework.web.context.ContextLoaderServlet + */ +public class Log4jConfigServlet extends HttpServlet { + + public void init() { + Log4jWebConfigurer.initLogging(getServletContext()); + } + + public void destroy() { + Log4jWebConfigurer.shutdownLogging(getServletContext()); + } + + + /** + * This should never even be called since no mapping to this servlet should + * ever be created in web.xml. That's why a correctly invoked Servlet 2.3 + * listener is much more appropriate for initialization work ;-) + */ + public void service(HttpServletRequest request, HttpServletResponse response) throws IOException { + getServletContext().log( + "Attempt to call service method on Log4jConfigServlet as [" + + request.getRequestURI() + "] was ignored"); + response.sendError(HttpServletResponse.SC_BAD_REQUEST); + } + + public String getServletInfo() { + return "Log4jConfigServlet for Servlet API 2.3 " + + "(deprecated in favor of Log4jConfigListener for Servlet API 2.4)"; + } + +} Index: 3rdParty_sources/spring/org/springframework/web/util/Log4jWebConfigurer.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/web/util/Log4jWebConfigurer.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/web/util/Log4jWebConfigurer.java 17 Aug 2012 15:16:09 -0000 1.1 @@ -0,0 +1,190 @@ +/* + * 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.web.util; + +import java.io.FileNotFoundException; + +import javax.servlet.ServletContext; + +import org.springframework.util.Log4jConfigurer; +import org.springframework.util.ResourceUtils; +import org.springframework.util.SystemPropertyUtils; + +/** + * Convenience class that performs custom log4j initialization for web environments, + * allowing for log file paths within the web application, with the option to + * perform automatic refresh checks (for runtime changes in logging configuration). + * + *

WARNING: Assumes an expanded WAR file, both for loading the configuration + * file and for writing the log files. If you want to keep your WAR unexpanded or + * don't need application-specific log files within the WAR directory, don't use + * log4j setup within the application (thus, don't use Log4jConfigListener or + * Log4jConfigServlet). Instead, use a global, VM-wide log4j setup (for example, + * in JBoss) or JDK 1.4's java.util.logging (which is global too). + * + *

Supports three init parameters at the servlet context level (that is, + * context-param entries in web.xml): + * + *

    + *
  • "log4jConfigLocation":
    + * Location of the log4j config file; either a "classpath:" location (e.g. + * "classpath:myLog4j.properties"), an absolute file URL (e.g. "file:C:/log4j.properties), + * or a plain path relative to the web application root directory (e.g. + * "/WEB-INF/log4j.properties"). If not specified, default log4j initialization + * will apply ("log4j.properties" or "log4j.xml" in the class path; see the + * log4j documentation for details). + *
  • "log4jRefreshInterval":
    + * Interval between config file refresh checks, in milliseconds. If not specified, + * no refresh checks will happen, which avoids starting log4j's watchdog thread. + *
  • "log4jExposeWebAppRoot":
    + * Whether the web app root system property should be exposed, allowing for log + * file paths relative to the web application root directory. Default is "true"; + * specify "false" to suppress expose of the web app root system property. See + * below for details on how to use this system property in log file locations. + *
+ * + *

Note: initLogging should be called before any other Spring activity + * (when using log4j), for proper initialization before any Spring logging attempts. + * + *

Log4j's watchdog thread will asynchronously check whether the timestamp + * of the config file has changed, using the given interval between checks. + * A refresh interval of 1000 milliseconds (one second), which allows to + * do on-demand log level changes with immediate effect, is not unfeasible. + + *

WARNING: Log4j's watchdog thread does not terminate until VM shutdown; + * in particular, it does not terminate on LogManager shutdown. Therefore, it is + * recommended to not use config file refreshing in a production J2EE + * environment; the watchdog thread would not stop on application shutdown there. + * + *

By default, this configurer automatically sets the web app root system property, + * for "${key}" substitutions within log file locations in the log4j config file, + * allowing for log file paths relative to the web application root directory. + * The default system property key is "webapp.root", to be used in a log4j config + * file like as follows: + * + *

log4j.appender.myfile.File=${webapp.root}/WEB-INF/demo.log + * + *

Alternatively, specify a unique context-param "webAppRootKey" per web application. + * For example, with "webAppRootKey = "demo.root": + * + *

log4j.appender.myfile.File=${demo.root}/WEB-INF/demo.log + * + *

WARNING: Some containers (like Tomcat) do not keep system properties + * separate per web app. You have to use unique "webAppRootKey" context-params per web + * app then, to avoid clashes. Other containers like Resin do isolate each web app's + * system properties: Here you can use the default key (i.e. no "webAppRootKey" + * context-param at all) without worrying. + * + * @author Juergen Hoeller + * @since 12.08.2003 + * @see org.springframework.util.Log4jConfigurer + * @see Log4jConfigListener + * @see Log4jConfigServlet + */ +public abstract class Log4jWebConfigurer { + + /** Parameter specifying the location of the log4j config file */ + public static final String CONFIG_LOCATION_PARAM = "log4jConfigLocation"; + + /** Parameter specifying the refresh interval for checking the log4j config file */ + public static final String REFRESH_INTERVAL_PARAM = "log4jRefreshInterval"; + + /** Parameter specifying whether to expose the web app root system property */ + public static final String EXPOSE_WEB_APP_ROOT_PARAM = "log4jExposeWebAppRoot"; + + + /** + * Initialize log4j, including setting the web app root system property. + * @param servletContext the current ServletContext + * @see WebUtils#setWebAppRootSystemProperty + */ + public static void initLogging(ServletContext servletContext) { + // Expose the web app root system property. + if (exposeWebAppRoot(servletContext)) { + WebUtils.setWebAppRootSystemProperty(servletContext); + } + + // Only perform custom log4j initialization in case of a config file. + String location = servletContext.getInitParameter(CONFIG_LOCATION_PARAM); + if (location != null) { + // Perform actual log4j initialization; else rely on log4j's default initialization. + try { + // Return a URL (e.g. "classpath:" or "file:") as-is; + // consider a plain file path as relative to the web application root directory. + if (!ResourceUtils.isUrl(location)) { + // Resolve system property placeholders before resolving real path. + location = SystemPropertyUtils.resolvePlaceholders(location); + location = WebUtils.getRealPath(servletContext, location); + } + + // Write log message to server log. + servletContext.log("Initializing log4j from [" + location + "]"); + + // Check whether refresh interval was specified. + String intervalString = servletContext.getInitParameter(REFRESH_INTERVAL_PARAM); + if (intervalString != null) { + // Initialize with refresh interval, i.e. with log4j's watchdog thread, + // checking the file in the background. + try { + long refreshInterval = Long.parseLong(intervalString); + Log4jConfigurer.initLogging(location, refreshInterval); + } + catch (NumberFormatException ex) { + throw new IllegalArgumentException("Invalid 'log4jRefreshInterval' parameter: " + ex.getMessage()); + } + } + else { + // Initialize without refresh check, i.e. without log4j's watchdog thread. + Log4jConfigurer.initLogging(location); + } + } + catch (FileNotFoundException ex) { + throw new IllegalArgumentException("Invalid 'log4jConfigLocation' parameter: " + ex.getMessage()); + } + } + } + + /** + * Shut down log4j, properly releasing all file locks + * and resetting the web app root system property. + * @param servletContext the current ServletContext + * @see WebUtils#removeWebAppRootSystemProperty + */ + public static void shutdownLogging(ServletContext servletContext) { + servletContext.log("Shutting down log4j"); + try { + Log4jConfigurer.shutdownLogging(); + } + finally { + // Remove the web app root system property. + if (exposeWebAppRoot(servletContext)) { + WebUtils.removeWebAppRootSystemProperty(servletContext); + } + } + } + + /** + * Return whether to expose the web app root system property, + * checking the corresponding ServletContext init parameter. + * @see #EXPOSE_WEB_APP_ROOT_PARAM + */ + private static boolean exposeWebAppRoot(ServletContext servletContext) { + String exposeWebAppRootParam = servletContext.getInitParameter(EXPOSE_WEB_APP_ROOT_PARAM); + return (exposeWebAppRootParam == null || Boolean.valueOf(exposeWebAppRootParam).booleanValue()); + } + +} Index: 3rdParty_sources/spring/org/springframework/web/util/NestedServletException.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/web/util/NestedServletException.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/web/util/NestedServletException.java 17 Aug 2012 15:16:09 -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.web.util; + +import javax.servlet.ServletException; + +import org.springframework.core.NestedExceptionUtils; + +/** + * Subclass of ServletException that properly handles a root cause in terms + * of message and stacktrace, just like NestedChecked/RuntimeException does. + * Note that the plain ServletException doesn't expose its root cause at all, + * neither in the exception message nor in printed stack traces! + * + *

The similarity between this class and the NestedChecked/RuntimeException + * class is unavoidable, as this class needs to derive from ServletException + * and cannot derive from NestedCheckedException. + * + * @author Juergen Hoeller + * @since 1.2.5 + * @see #getMessage + * @see #printStackTrace + * @see org.springframework.core.NestedCheckedException + * @see org.springframework.core.NestedRuntimeException + */ +public class NestedServletException extends ServletException { + + /** Use serialVersionUID from Spring 1.2 for interoperability */ + private static final long serialVersionUID = -5292377985529381145L; + + + /** + * Construct a NestedServletException with the specified detail message. + * @param msg the detail message + */ + public NestedServletException(String msg) { + super(msg); + } + + /** + * Construct a NestedServletException with the specified detail message + * and nested exception. + * @param msg the detail message + * @param cause the nested exception + */ + public NestedServletException(String msg, Throwable cause) { + super(msg, cause); + // Set JDK 1.4 exception chain cause if not done by ServletException class already + // (this differs between Servlet API versions). + if (getCause() == null) { + initCause(cause); + } + } + + + /** + * Return the detail message, including the message from the nested exception + * if there is one. + */ + public String getMessage() { + return NestedExceptionUtils.buildMessage(super.getMessage(), getCause()); + } + +} Index: 3rdParty_sources/spring/org/springframework/web/util/TagUtils.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/web/util/TagUtils.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/web/util/TagUtils.java 17 Aug 2012 15:16:09 -0000 1.1 @@ -0,0 +1,136 @@ +/* + * 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.web.util; + +import javax.servlet.jsp.PageContext; +import javax.servlet.jsp.tagext.Tag; + +import org.springframework.util.Assert; + +/** + * Utility class for tag library related code, exposing functionality + * such as translating {@link String Strings} to web scopes. + * + *

+ *

    + *
  • page will be transformed to + * {@link javax.servlet.jsp.PageContext#PAGE_SCOPE PageContext.PAGE_SCOPE} + *
  • request will be transformed to + * {@link javax.servlet.jsp.PageContext#REQUEST_SCOPE PageContext.REQUEST_SCOPE} + *
  • session will be transformed to + * {@link javax.servlet.jsp.PageContext#SESSION_SCOPE PageContext.SESSION_SCOPE} + *
  • application will be transformed to + * {@link javax.servlet.jsp.PageContext#APPLICATION_SCOPE PageContext.APPLICATION_SCOPE} + *
+ * + * @author Alef Arendsen + * @author Rob Harrop + * @author Juergen Hoeller + * @author Rick Evans + */ +public abstract class TagUtils { + + /** Constant identifying the page scope */ + public static final String SCOPE_PAGE = "page"; + + /** Constant identifying the request scope */ + public static final String SCOPE_REQUEST = "request"; + + /** Constant identifying the session scope */ + public static final String SCOPE_SESSION = "session"; + + /** Constant identifying the application scope */ + public static final String SCOPE_APPLICATION = "application"; + + + /** + * Determines the scope for a given input String. + *

If the String does not match 'request', 'session', + * 'page' or 'application', the method will return {@link PageContext#PAGE_SCOPE}. + * @param scope the String to inspect + * @return the scope found, or {@link PageContext#PAGE_SCOPE} if no scope matched + * @throws IllegalArgumentException if the supplied scope is null + */ + public static int getScope(String scope) { + Assert.notNull(scope, "Scope to search for cannot be null"); + if (scope.equals(SCOPE_REQUEST)) { + return PageContext.REQUEST_SCOPE; + } + else if (scope.equals(SCOPE_SESSION)) { + return PageContext.SESSION_SCOPE; + } + else if (scope.equals(SCOPE_APPLICATION)) { + return PageContext.APPLICATION_SCOPE; + } + else { + return PageContext.PAGE_SCOPE; + } + } + + /** + * Determine whether the supplied {@link Tag} has any ancestor tag + * of the supplied type. + * @param tag the tag whose ancestors are to be checked + * @param ancestorTagClass the ancestor {@link Class} being searched for + * @return true if the supplied {@link Tag} has any ancestor tag + * of the supplied type + * @throws IllegalArgumentException if either of the supplied arguments is null; + * or if the supplied ancestorTagClass is not type-assignable to + * the {@link Tag} class + */ + public static boolean hasAncestorOfType(Tag tag, Class ancestorTagClass) { + Assert.notNull(tag, "Tag cannot be null"); + Assert.notNull(ancestorTagClass, "Ancestor tag class cannot be null"); + if (!Tag.class.isAssignableFrom(ancestorTagClass)) { + throw new IllegalArgumentException( + "Class '" + ancestorTagClass.getName() + "' is not a valid Tag type"); + } + Tag ancestor = tag.getParent(); + while (ancestor != null) { + if (ancestorTagClass.isAssignableFrom(ancestor.getClass())) { + return true; + } + ancestor = ancestor.getParent(); + } + return false; + } + + /** + * Determine whether the supplied {@link Tag} has any ancestor tag + * of the supplied type, throwing an {@link IllegalStateException} + * if not. + * @param tag the tag whose ancestors are to be checked + * @param ancestorTagClass the ancestor {@link Class} being searched for + * @param tagName the name of the tag; for example 'option' + * @param ancestorTagName the name of the ancestor tag; for example 'select' + * @throws IllegalStateException if the supplied tag does not + * have a tag of the supplied parentTagClass as an ancestor + * @throws IllegalArgumentException if any of the supplied arguments is null, + * or in the case of the {@link String}-typed arguments, is composed wholly + * of whitespace; or if the supplied ancestorTagClass is not + * type-assignable to the {@link Tag} class + * @see #hasAncestorOfType(javax.servlet.jsp.tagext.Tag, Class) + */ + public static void assertHasAncestorOfType(Tag tag, Class ancestorTagClass, String tagName, String ancestorTagName) { + Assert.hasText(tagName, "'tagName' must not be empty"); + Assert.hasText(ancestorTagName, "'ancestorTagName' must not be empty"); + if (!TagUtils.hasAncestorOfType(tag, ancestorTagClass)) { + throw new IllegalStateException("The '" + tagName + "' tag can only be used inside a valid '" + ancestorTagName + "' tag."); + } + } + +} Index: 3rdParty_sources/spring/org/springframework/web/util/UrlPathHelper.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/web/util/UrlPathHelper.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/web/util/UrlPathHelper.java 17 Aug 2012 15:16:09 -0000 1.1 @@ -0,0 +1,357 @@ +/* + * 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.web.util; + +import java.io.UnsupportedEncodingException; +import java.net.URLDecoder; + +import javax.servlet.http.HttpServletRequest; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import org.springframework.util.StringUtils; + +/** + * Helper class for URL path matching. Provides support for URL paths in + * RequestDispatcher includes and support for consistent URL decoding. + * + *

Used by {@link org.springframework.web.servlet.handler.AbstractUrlHandlerMapping}, + * {@link org.springframework.web.servlet.mvc.multiaction.AbstractUrlMethodNameResolver} + * and {@link org.springframework.web.servlet.support.RequestContext} for path matching + * and/or URI determination. + * + * @author Juergen Hoeller + * @author Rob Harrop + * @since 14.01.2004 + */ +public class UrlPathHelper { + + /** + * @deprecated as of Spring 2.0, in favor of WebUtils.INCLUDE_REQUEST_URI_ATTRIBUTE + * @see org.springframework.web.util.WebUtils#INCLUDE_REQUEST_URI_ATTRIBUTE + */ + public static final String INCLUDE_URI_REQUEST_ATTRIBUTE = WebUtils.INCLUDE_REQUEST_URI_ATTRIBUTE; + + /** + * @deprecated as of Spring 2.0, in favor of WebUtils.INCLUDE_CONTEXT_PATH_ATTRIBUTE + * @see org.springframework.web.util.WebUtils#INCLUDE_CONTEXT_PATH_ATTRIBUTE + */ + public static final String INCLUDE_CONTEXT_PATH_REQUEST_ATTRIBUTE = WebUtils.INCLUDE_CONTEXT_PATH_ATTRIBUTE; + + /** + * @deprecated as of Spring 2.0, in favor of WebUtils.INCLUDE_SERVLET_PATH_ATTRIBUTE + * @see org.springframework.web.util.WebUtils#INCLUDE_SERVLET_PATH_ATTRIBUTE + */ + public static final String INCLUDE_SERVLET_PATH_REQUEST_ATTRIBUTE = WebUtils.INCLUDE_SERVLET_PATH_ATTRIBUTE; + + + private final Log logger = LogFactory.getLog(getClass()); + + private boolean alwaysUseFullPath = false; + + private boolean urlDecode = true; + + private String defaultEncoding = WebUtils.DEFAULT_CHARACTER_ENCODING; + + + /** + * Set if URL lookup should always use full path within current servlet + * context. Else, the path within the current servlet mapping is used + * if applicable (i.e. in the case of a ".../*" servlet mapping in web.xml). + * Default is "false". + */ + public void setAlwaysUseFullPath(boolean alwaysUseFullPath) { + this.alwaysUseFullPath = alwaysUseFullPath; + } + + /** + * Set if context path and request URI should be URL-decoded. + * Both are returned undecoded by the Servlet API, + * in contrast to the servlet path. + *

Uses either the request encoding or the default encoding according + * to the Servlet spec (ISO-8859-1). + *

Default is "true", as of Spring 2.5. + * @see #getServletPath + * @see #getContextPath + * @see #getRequestUri + * @see WebUtils#DEFAULT_CHARACTER_ENCODING + * @see javax.servlet.ServletRequest#getCharacterEncoding() + * @see java.net.URLDecoder#decode(String, String) + */ + public void setUrlDecode(boolean urlDecode) { + this.urlDecode = urlDecode; + } + + /** + * Set the default character encoding to use for URL decoding. + * Default is ISO-8859-1, according to the Servlet spec. + *

If the request specifies a character encoding itself, the request + * encoding will override this setting. This also allows for generically + * overriding the character encoding in a filter that invokes the + * ServletRequest.setCharacterEncoding method. + * @param defaultEncoding the character encoding to use + * @see #determineEncoding + * @see javax.servlet.ServletRequest#getCharacterEncoding() + * @see javax.servlet.ServletRequest#setCharacterEncoding(String) + * @see WebUtils#DEFAULT_CHARACTER_ENCODING + */ + public void setDefaultEncoding(String defaultEncoding) { + this.defaultEncoding = defaultEncoding; + } + + /** + * Return the default character encoding to use for URL decoding. + */ + protected String getDefaultEncoding() { + return this.defaultEncoding; + } + + + /** + * Return the mapping lookup path for the given request, within the current + * servlet mapping if applicable, else within the web application. + *

Detects include request URL if called within a RequestDispatcher include. + * @param request current HTTP request + * @return the lookup path + * @see #getPathWithinApplication + * @see #getPathWithinServletMapping + */ + public String getLookupPathForRequest(HttpServletRequest request) { + // Always use full path within current servlet context? + if (this.alwaysUseFullPath) { + return getPathWithinApplication(request); + } + // Else, use path within current servlet mapping if applicable + String rest = getPathWithinServletMapping(request); + if (!"".equals(rest)) { + return rest; + } + else { + return getPathWithinApplication(request); + } + } + + /** + * Return the path within the servlet mapping for the given request, + * i.e. the part of the request's URL beyond the part that called the servlet, + * or "" if the whole URL has been used to identify the servlet. + *

Detects include request URL if called within a RequestDispatcher include. + *

E.g.: servlet mapping = "/test/*"; request URI = "/test/a" -> "/a". + *

E.g.: servlet mapping = "/test"; request URI = "/test" -> "". + *

E.g.: servlet mapping = "/*.test"; request URI = "/a.test" -> "". + * @param request current HTTP request + * @return the path within the servlet mapping, or "" + */ + public String getPathWithinServletMapping(HttpServletRequest request) { + String pathWithinApp = getPathWithinApplication(request); + String servletPath = getServletPath(request); + if (pathWithinApp.startsWith(servletPath)) { + // Normal case: URI contains servlet path. + return pathWithinApp.substring(servletPath.length()); + } + else { + // Special case: URI is different from servlet path. + // Can happen e.g. with index page: URI="/", servletPath="/index.html" + // Use servlet path in this case, as it indicates the actual target path. + return servletPath; + } + } + + /** + * Return the path within the web application for the given request. + *

Detects include request URL if called within a RequestDispatcher include. + * @param request current HTTP request + * @return the path within the web application + */ + public String getPathWithinApplication(HttpServletRequest request) { + String contextPath = getContextPath(request); + String requestUri = getRequestUri(request); + if (StringUtils.startsWithIgnoreCase(requestUri, contextPath)) { + // Normal case: URI contains context path. + String path = requestUri.substring(contextPath.length()); + return (StringUtils.hasText(path) ? path : "/"); + } + else { + // Special case: rather unusual. + return requestUri; + } + } + + + /** + * Return the request URI for the given request, detecting an include request + * URL if called within a RequestDispatcher include. + *

As the value returned by request.getRequestURI() is not + * decoded by the servlet container, this method will decode it. + *

The URI that the web container resolves should be correct, but some + * containers like JBoss/Jetty incorrectly include ";" strings like ";jsessionid" + * in the URI. This method cuts off such incorrect appendices. + * @param request current HTTP request + * @return the request URI + */ + public String getRequestUri(HttpServletRequest request) { + String uri = (String) request.getAttribute(WebUtils.INCLUDE_REQUEST_URI_ATTRIBUTE); + if (uri == null) { + uri = request.getRequestURI(); + } + return decodeAndCleanUriString(request, uri); + } + + /** + * Return the context path for the given request, detecting an include request + * URL if called within a RequestDispatcher include. + *

As the value returned by request.getContextPath() is not + * decoded by the servlet container, this method will decode it. + * @param request current HTTP request + * @return the context path + */ + public String getContextPath(HttpServletRequest request) { + String contextPath = (String) request.getAttribute(WebUtils.INCLUDE_CONTEXT_PATH_ATTRIBUTE); + if (contextPath == null) { + contextPath = request.getContextPath(); + } + if ("/".equals(contextPath)) { + // Invalid case, but happens for includes on Jetty: silently adapt it. + contextPath = ""; + } + return decodeRequestString(request, contextPath); + } + + /** + * Return the servlet path for the given request, regarding an include request + * URL if called within a RequestDispatcher include. + *

As the value returned by request.getServletPath() is already + * decoded by the servlet container, this method will not attempt to decode it. + * @param request current HTTP request + * @return the servlet path + */ + public String getServletPath(HttpServletRequest request) { + String servletPath = (String) request.getAttribute(WebUtils.INCLUDE_SERVLET_PATH_ATTRIBUTE); + if (servletPath == null) { + servletPath = request.getServletPath(); + } + return servletPath; + } + + + /** + * Return the request URI for root of the given request. If this is a forwarded request, + * correctly resolves to the request URI of the original request. + *

Relies on the Servlet 2.4 'forward' attributes. These attributes may be set by + * other components when running in a Servlet 2.3 environment. + */ + public String getOriginatingRequestUri(HttpServletRequest request) { + String uri = (String) request.getAttribute(WebUtils.FORWARD_REQUEST_URI_ATTRIBUTE); + if (uri == null) { + uri = request.getRequestURI(); + } + return decodeAndCleanUriString(request, uri); + } + + /** + * Return the context path for the given request, detecting an include request + * URL if called within a RequestDispatcher include. + *

As the value returned by request.getContextPath() is not + * decoded by the servlet container, this method will decode it. + *

Relies on the Servlet 2.4 'forward' attributes. These attributes may be set by + * other components when running in a Servlet 2.3 environment. + * @param request current HTTP request + * @return the context path + */ + public String getOriginatingContextPath(HttpServletRequest request) { + String contextPath = (String) request.getAttribute(WebUtils.FORWARD_CONTEXT_PATH_ATTRIBUTE); + if (contextPath == null) { + contextPath = request.getContextPath(); + } + return decodeRequestString(request, contextPath); + } + + /** + * Return the request URI for root of the given request. If this is a forwarded request, + * correctly resolves to the request URI of the original request. + *

Relies on the Servlet 2.4 'forward' attributes. These attributes may be set by + * other components when running in a Servlet 2.3 environment. + * @param request current HTTP request + * @return the query string + */ + public String getOriginatingQueryString(HttpServletRequest request) { + String queryString = (String) request.getAttribute(WebUtils.FORWARD_QUERY_STRING_ATTRIBUTE); + if (queryString == null) { + queryString = request.getQueryString(); + } + return queryString; + } + + + /** + * Decode the supplied URI string and strips any extraneous portion after a ';'. + */ + private String decodeAndCleanUriString(HttpServletRequest request, String uri) { + uri = decodeRequestString(request, uri); + int semicolonIndex = uri.indexOf(';'); + return (semicolonIndex != -1 ? uri.substring(0, semicolonIndex) : uri); + } + + /** + * Decode the given source string with a URLDecoder. The encoding will be taken + * from the request, falling back to the default "ISO-8859-1". + *

The default implementation uses URLDecoder.decode(input, enc). + * @param request current HTTP request + * @param source the String to decode + * @return the decoded String + * @see WebUtils#DEFAULT_CHARACTER_ENCODING + * @see javax.servlet.ServletRequest#getCharacterEncoding + * @see java.net.URLDecoder#decode(String, String) + * @see java.net.URLDecoder#decode(String) + */ + public String decodeRequestString(HttpServletRequest request, String source) { + if (this.urlDecode) { + String enc = determineEncoding(request); + try { + return URLDecoder.decode(source, enc); + } + catch (UnsupportedEncodingException ex) { + if (logger.isWarnEnabled()) { + logger.warn("Could not decode request string [" + source + "] with encoding '" + enc + + "': falling back to platform default encoding; exception message: " + ex.getMessage()); + } + return URLDecoder.decode(source); + } + } + return source; + } + + /** + * Determine the encoding for the given request. + * Can be overridden in subclasses. + *

The default implementation checks the request encoding, + * falling back to the default encoding specified for this resolver. + * @param request current HTTP request + * @return the encoding for the request (never null) + * @see javax.servlet.ServletRequest#getCharacterEncoding() + * @see #setDefaultEncoding + */ + protected String determineEncoding(HttpServletRequest request) { + String enc = request.getCharacterEncoding(); + if (enc == null) { + enc = getDefaultEncoding(); + } + return enc; + } + +} Index: 3rdParty_sources/spring/org/springframework/web/util/WebAppRootListener.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/web/util/WebAppRootListener.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/web/util/WebAppRootListener.java 17 Aug 2012 15:16:09 -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.web.util; + +import javax.servlet.ServletContextEvent; +import javax.servlet.ServletContextListener; + +/** + * Listener that sets a system property to the web application root directory. + * The key of the system property can be defined with the "webAppRootKey" init + * parameter at the servlet context level (i.e. context-param in web.xml), + * the default key is "webapp.root". + * + *

Can be used for toolkits that support substition with system properties + * (i.e. System.getProperty values), like log4j's "${key}" syntax within log + * file locations. + * + *

Note: This listener should be placed before ContextLoaderListener in web.xml, + * at least when used for log4j. Log4jConfigListener sets the system property + * implicitly, so there's no need for this listener in addition to it. + * + *

WARNING: Some containers, e.g. Tomcat, do NOT keep system properties separate + * per web app. You have to use unique "webAppRootKey" context-params per web app + * then, to avoid clashes. Other containers like Resin do isolate each web app's + * system properties: Here you can use the default key (i.e. no "webAppRootKey" + * context-param at all) without worrying. + * + *

WARNING: The WAR file containing the web application needs to be expanded + * to allow for setting the web app root system property. This is by default not + * the case when a WAR file gets deployed to WebLogic, for example. Do not use + * this listener in such an environment! + * + * @author Juergen Hoeller + * @since 18.04.2003 + * @see WebUtils#setWebAppRootSystemProperty + * @see Log4jConfigListener + * @see java.lang.System#getProperty + */ +public class WebAppRootListener implements ServletContextListener { + + public void contextInitialized(ServletContextEvent event) { + WebUtils.setWebAppRootSystemProperty(event.getServletContext()); + } + + public void contextDestroyed(ServletContextEvent event) { + WebUtils.removeWebAppRootSystemProperty(event.getServletContext()); + } + +} Index: 3rdParty_sources/spring/org/springframework/web/util/WebUtils.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/web/util/WebUtils.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/web/util/WebUtils.java 17 Aug 2012 15:16:09 -0000 1.1 @@ -0,0 +1,679 @@ +/* + * 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.web.util; + +import java.io.File; +import java.io.FileNotFoundException; +import java.util.Enumeration; +import java.util.Iterator; +import java.util.Map; +import java.util.TreeMap; + +import javax.servlet.ServletContext; +import javax.servlet.ServletRequest; +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; + +import org.springframework.util.Assert; +import org.springframework.util.StringUtils; + +/** + * Miscellaneous utilities for web applications. + * Used by various framework classes. + * + * @author Rod Johnson + * @author Juergen Hoeller + */ +public abstract class WebUtils { + + /** + * Standard Servlet 2.3+ spec request attributes for include URI and paths. + *

If included via a RequestDispatcher, the current resource will see the + * originating request. Its own URI and paths are exposed as request attributes. + */ + public static final String INCLUDE_REQUEST_URI_ATTRIBUTE = "javax.servlet.include.request_uri"; + public static final String INCLUDE_CONTEXT_PATH_ATTRIBUTE = "javax.servlet.include.context_path"; + public static final String INCLUDE_SERVLET_PATH_ATTRIBUTE = "javax.servlet.include.servlet_path"; + public static final String INCLUDE_PATH_INFO_ATTRIBUTE = "javax.servlet.include.path_info"; + public static final String INCLUDE_QUERY_STRING_ATTRIBUTE = "javax.servlet.include.query_string"; + + /** + * Standard Servlet 2.4+ spec request attributes for forward URI and paths. + *

If forwarded to via a RequestDispatcher, the current resource will see its + * own URI and paths. The originating URI and paths are exposed as request attributes. + */ + public static final String FORWARD_REQUEST_URI_ATTRIBUTE = "javax.servlet.forward.request_uri"; + public static final String FORWARD_CONTEXT_PATH_ATTRIBUTE = "javax.servlet.forward.context_path"; + public static final String FORWARD_SERVLET_PATH_ATTRIBUTE = "javax.servlet.forward.servlet_path"; + public static final String FORWARD_PATH_INFO_ATTRIBUTE = "javax.servlet.forward.path_info"; + public static final String FORWARD_QUERY_STRING_ATTRIBUTE = "javax.servlet.forward.query_string"; + + /** + * Standard Servlet 2.3+ spec request attributes for error pages. + *

To be exposed to JSPs that are marked as error pages, when forwarding + * to them directly rather than through the servlet container's error page + * resolution mechanism. + */ + public static final String ERROR_STATUS_CODE_ATTRIBUTE = "javax.servlet.error.status_code"; + public static final String ERROR_EXCEPTION_TYPE_ATTRIBUTE = "javax.servlet.error.exception_type"; + public static final String ERROR_MESSAGE_ATTRIBUTE = "javax.servlet.error.message"; + public static final String ERROR_EXCEPTION_ATTRIBUTE = "javax.servlet.error.exception"; + public static final String ERROR_REQUEST_URI_ATTRIBUTE = "javax.servlet.error.request_uri"; + public static final String ERROR_SERVLET_NAME_ATTRIBUTE = "javax.servlet.error.servlet_name"; + + + /** + * Prefix of the charset clause in a content type String: ";charset=" + */ + public static final String CONTENT_TYPE_CHARSET_PREFIX = ";charset="; + + /** + * Default character encoding to use when request.getCharacterEncoding + * returns null, according to the Servlet spec. + * @see ServletRequest#getCharacterEncoding + */ + public static final String DEFAULT_CHARACTER_ENCODING = "ISO-8859-1"; + + /** + * Standard Servlet spec context attribute that specifies a temporary + * directory for the current web application, of type java.io.File. + */ + public static final String TEMP_DIR_CONTEXT_ATTRIBUTE = "javax.servlet.context.tempdir"; + + /** + * HTML escape parameter at the servlet context level + * (i.e. a context-param in web.xml): "defaultHtmlEscape". + */ + public static final String HTML_ESCAPE_CONTEXT_PARAM = "defaultHtmlEscape"; + + /** + * Web app root key parameter at the servlet context level + * (i.e. a context-param in web.xml): "webAppRootKey". + */ + public static final String WEB_APP_ROOT_KEY_PARAM = "webAppRootKey"; + + /** Default web app root key: "webapp.root" */ + public static final String DEFAULT_WEB_APP_ROOT_KEY = "webapp.root"; + + /** Name suffixes in case of image buttons */ + public static final String[] SUBMIT_IMAGE_SUFFIXES = {".x", ".y"}; + + /** Key for the mutex session attribute */ + public static final String SESSION_MUTEX_ATTRIBUTE = WebUtils.class.getName() + ".MUTEX"; + + + /** + * Set a system property to the web application root directory. + * The key of the system property can be defined with the "webAppRootKey" + * context-param in web.xml. Default is "webapp.root". + *

Can be used for tools that support substition with System.getProperty + * values, like log4j's "${key}" syntax within log file locations. + * @param servletContext the servlet context of the web application + * @throws IllegalStateException if the system property is already set, + * or if the WAR file is not expanded + * @see #WEB_APP_ROOT_KEY_PARAM + * @see #DEFAULT_WEB_APP_ROOT_KEY + * @see WebAppRootListener + * @see Log4jWebConfigurer + */ + public static void setWebAppRootSystemProperty(ServletContext servletContext) throws IllegalStateException { + Assert.notNull(servletContext, "ServletContext must not be null"); + String root = servletContext.getRealPath("/"); + if (root == null) { + throw new IllegalStateException( + "Cannot set web app root system property when WAR file is not expanded"); + } + String param = servletContext.getInitParameter(WEB_APP_ROOT_KEY_PARAM); + String key = (param != null ? param : DEFAULT_WEB_APP_ROOT_KEY); + String oldValue = System.getProperty(key); + if (oldValue != null && !StringUtils.pathEquals(oldValue, root)) { + throw new IllegalStateException( + "Web app root system property already set to different value: '" + + key + "' = [" + oldValue + "] instead of [" + root + "] - " + + "Choose unique values for the 'webAppRootKey' context-param in your web.xml files!"); + } + System.setProperty(key, root); + servletContext.log("Set web app root system property: '" + key + "' = [" + root + "]"); + } + + /** + * Remove the system property that points to the web app root directory. + * To be called on shutdown of the web application. + * @param servletContext the servlet context of the web application + * @see #setWebAppRootSystemProperty + */ + public static void removeWebAppRootSystemProperty(ServletContext servletContext) { + Assert.notNull(servletContext, "ServletContext must not be null"); + String param = servletContext.getInitParameter(WEB_APP_ROOT_KEY_PARAM); + String key = (param != null ? param : DEFAULT_WEB_APP_ROOT_KEY); + System.getProperties().remove(key); + } + + /** + * Return whether default HTML escaping is enabled for the web application, + * i.e. the value of the "defaultHtmlEscape" context-param in web.xml + * (if any). Falls back to false in case of no explicit default given. + * @param servletContext the servlet context of the web application + * @return whether default HTML escaping is enabled (default is false) + */ + public static boolean isDefaultHtmlEscape(ServletContext servletContext) { + if (servletContext == null) { + return false; + } + String param = servletContext.getInitParameter(HTML_ESCAPE_CONTEXT_PARAM); + return Boolean.valueOf(param).booleanValue(); + } + + /** + * Return whether default HTML escaping is enabled for the web application, + * i.e. the value of the "defaultHtmlEscape" context-param in web.xml + * (if any). + *

This method differentiates between no param specified at all and + * an actual boolean value specified, allowing to have a context-specific + * default in case of no setting at the global level. + * @param servletContext the servlet context of the web application + * @return whether default HTML escaping is enabled (null = no explicit default) + */ + public static Boolean getDefaultHtmlEscape(ServletContext servletContext) { + if (servletContext == null) { + return null; + } + Assert.notNull(servletContext, "ServletContext must not be null"); + String param = servletContext.getInitParameter(HTML_ESCAPE_CONTEXT_PARAM); + return (StringUtils.hasText(param)? Boolean.valueOf(param) : null); + } + + /** + * Return the temporary directory for the current web application, + * as provided by the servlet container. + * @param servletContext the servlet context of the web application + * @return the File representing the temporary directory + */ + public static File getTempDir(ServletContext servletContext) { + Assert.notNull(servletContext, "ServletContext must not be null"); + return (File) servletContext.getAttribute(TEMP_DIR_CONTEXT_ATTRIBUTE); + } + + /** + * Return the real path of the given path within the web application, + * as provided by the servlet container. + *

Prepends a slash if the path does not already start with a slash, + * and throws a FileNotFoundException if the path cannot be resolved to + * a resource (in contrast to ServletContext's getRealPath, + * which returns null). + * @param servletContext the servlet context of the web application + * @param path the path within the web application + * @return the corresponding real path + * @throws FileNotFoundException if the path cannot be resolved to a resource + * @see javax.servlet.ServletContext#getRealPath + */ + public static String getRealPath(ServletContext servletContext, String path) throws FileNotFoundException { + Assert.notNull(servletContext, "ServletContext must not be null"); + // Interpret location as relative to the web application root directory. + if (!path.startsWith("/")) { + path = "/" + path; + } + String realPath = servletContext.getRealPath(path); + if (realPath == null) { + throw new FileNotFoundException( + "ServletContext resource [" + path + "] cannot be resolved to absolute file path - " + + "web application archive not expanded?"); + } + return realPath; + } + + + /** + * Determine the session id of the given request, if any. + * @param request current HTTP request + * @return the session id, or null if none + */ + public static String getSessionId(HttpServletRequest request) { + Assert.notNull(request, "Request must not be null"); + HttpSession session = request.getSession(false); + return (session != null ? session.getId() : null); + } + + /** + * Check the given request for a session attribute of the given name. + * Returns null if there is no session or if the session has no such attribute. + * Does not create a new session if none has existed before! + * @param request current HTTP request + * @param name the name of the session attribute + * @return the value of the session attribute, or null if not found + */ + public static Object getSessionAttribute(HttpServletRequest request, String name) { + Assert.notNull(request, "Request must not be null"); + HttpSession session = request.getSession(false); + return (session != null ? session.getAttribute(name) : null); + } + + /** + * Check the given request for a session attribute of the given name. + * Throws an exception if there is no session or if the session has no such + * attribute. Does not create a new session if none has existed before! + * @param request current HTTP request + * @param name the name of the session attribute + * @return the value of the session attribute, or null if not found + * @throws IllegalStateException if the session attribute could not be found + */ + public static Object getRequiredSessionAttribute(HttpServletRequest request, String name) + throws IllegalStateException { + + Object attr = getSessionAttribute(request, name); + if (attr == null) { + throw new IllegalStateException("No session attribute '" + name + "' found"); + } + return attr; + } + + /** + * Set the session attribute with the given name to the given value. + * Removes the session attribute if value is null, if a session existed at all. + * Does not create a new session if not necessary! + * @param request current HTTP request + * @param name the name of the session attribute + * @param value the value of the session attribute + */ + public static void setSessionAttribute(HttpServletRequest request, String name, Object value) { + Assert.notNull(request, "Request must not be null"); + if (value != null) { + request.getSession().setAttribute(name, value); + } + else { + HttpSession session = request.getSession(false); + if (session != null) { + session.removeAttribute(name); + } + } + } + + /** + * Get the specified session attribute, creating and setting a new attribute if + * no existing found. The given class needs to have a public no-arg constructor. + * Useful for on-demand state objects in a web tier, like shopping carts. + * @param session current HTTP session + * @param name the name of the session attribute + * @param clazz the class to instantiate for a new attribute + * @return the value of the session attribute, newly created if not found + * @throws IllegalArgumentException if the session attribute could not be instantiated + */ + public static Object getOrCreateSessionAttribute(HttpSession session, String name, Class clazz) + throws IllegalArgumentException { + + Assert.notNull(session, "Session must not be null"); + Object sessionObject = session.getAttribute(name); + if (sessionObject == null) { + try { + sessionObject = clazz.newInstance(); + } + catch (InstantiationException ex) { + throw new IllegalArgumentException( + "Could not instantiate class [" + clazz.getName() + + "] for session attribute '" + name + "': " + ex.getMessage()); + } + catch (IllegalAccessException ex) { + throw new IllegalArgumentException( + "Could not access default constructor of class [" + clazz.getName() + + "] for session attribute '" + name + "': " + ex.getMessage()); + } + session.setAttribute(name, sessionObject); + } + return sessionObject; + } + + /** + * Return the best available mutex for the given session: + * that is, an object to synchronize on for the given session. + *

Returns the session mutex attribute if available; usually, + * this means that the HttpSessionMutexListener needs to be defined + * in web.xml. Falls back to the HttpSession itself + * if no mutex attribute found. + *

The session mutex is guaranteed to be the same object during + * the entire lifetime of the session, available under the key defined + * by the SESSION_MUTEX_ATTRIBUTE constant. It serves as a + * safe reference to synchronize on for locking on the current session. + *

In many cases, the HttpSession reference itself is a safe mutex + * as well, since it will always be the same object reference for the + * same active logical session. However, this is not guaranteed across + * different servlet containers; the only 100% safe way is a session mutex. + * @param session the HttpSession to find a mutex for + * @return the mutex object (never null) + * @see #SESSION_MUTEX_ATTRIBUTE + * @see HttpSessionMutexListener + */ + public static Object getSessionMutex(HttpSession session) { + Assert.notNull(session, "Session must not be null"); + Object mutex = session.getAttribute(SESSION_MUTEX_ATTRIBUTE); + if (mutex == null) { + mutex = session; + } + return mutex; + } + + + /** + * Determine whether the given request is an include request, + * that is, not a top-level HTTP request coming in from the outside. + *

Checks the presence of the "javax.servlet.include.request_uri" + * request attribute. Could check any request attribute that is only + * present in an include request. + * @param request current servlet request + * @return whether the given request is an include request + */ + public static boolean isIncludeRequest(ServletRequest request) { + return (request.getAttribute(INCLUDE_REQUEST_URI_ATTRIBUTE) != null); + } + + /** + * Expose the current request URI and paths as {@link javax.servlet.http.HttpServletRequest} + * attributes under the keys defined in the Servlet 2.4 specification, + * for containers that implement 2.3 or an earlier version of the Servlet API: + * javax.servlet.forward.request_uri, + * javax.servlet.forward.context_path, + * javax.servlet.forward.servlet_path, + * javax.servlet.forward.path_info, + * javax.servlet.forward.query_string. + *

Does not override values if already present, to not cause conflicts + * with the attributes exposed by Servlet 2.4+ containers themselves. + * @param request current servlet request + */ + public static void exposeForwardRequestAttributes(HttpServletRequest request) { + exposeRequestAttributeIfNotPresent(request, FORWARD_REQUEST_URI_ATTRIBUTE, request.getRequestURI()); + exposeRequestAttributeIfNotPresent(request, FORWARD_CONTEXT_PATH_ATTRIBUTE, request.getContextPath()); + exposeRequestAttributeIfNotPresent(request, FORWARD_SERVLET_PATH_ATTRIBUTE, request.getServletPath()); + exposeRequestAttributeIfNotPresent(request, FORWARD_PATH_INFO_ATTRIBUTE, request.getPathInfo()); + exposeRequestAttributeIfNotPresent(request, FORWARD_QUERY_STRING_ATTRIBUTE, request.getQueryString()); + } + + /** + * Expose the Servlet spec's error attributes as {@link javax.servlet.http.HttpServletRequest} + * attributes under the keys defined in the Servlet 2.3 specification, for error pages that + * are rendered directly rather than through the Servlet container's error page resolution: + * javax.servlet.error.status_code, + * javax.servlet.error.exception_type, + * javax.servlet.error.message, + * javax.servlet.error.exception, + * javax.servlet.error.request_uri, + * javax.servlet.error.servlet_name. + *

Does not override values if already present, to respect attribute values + * that have been exposed explicitly before. + *

Exposes status code 200 by default. Set the "javax.servlet.error.status_code" + * attribute explicitly (before or after) in order to expose a different status code. + * @param request current servlet request + * @param ex the exception encountered + * @param servletName the name of the offending servlet + */ + public static void exposeErrorRequestAttributes(HttpServletRequest request, Throwable ex, String servletName) { + exposeRequestAttributeIfNotPresent(request, ERROR_STATUS_CODE_ATTRIBUTE, new Integer(HttpServletResponse.SC_OK)); + exposeRequestAttributeIfNotPresent(request, ERROR_EXCEPTION_TYPE_ATTRIBUTE, ex.getClass()); + exposeRequestAttributeIfNotPresent(request, ERROR_MESSAGE_ATTRIBUTE, ex.getMessage()); + exposeRequestAttributeIfNotPresent(request, ERROR_EXCEPTION_ATTRIBUTE, ex); + exposeRequestAttributeIfNotPresent(request, ERROR_REQUEST_URI_ATTRIBUTE, request.getRequestURI()); + exposeRequestAttributeIfNotPresent(request, ERROR_SERVLET_NAME_ATTRIBUTE, servletName); + } + + /** + * Expose the specified request attribute if not already present. + * @param request current servlet request + * @param name the name of the attribute + * @param value the suggested value of the attribute + */ + private static void exposeRequestAttributeIfNotPresent(ServletRequest request, String name, Object value) { + if (request.getAttribute(name) == null) { + request.setAttribute(name, value); + } + } + + /** + * Clear the Servlet spec's error attributes as {@link javax.servlet.http.HttpServletRequest} + * attributes under the keys defined in the Servlet 2.3 specification: + * javax.servlet.error.status_code, + * javax.servlet.error.exception_type, + * javax.servlet.error.message, + * javax.servlet.error.exception, + * javax.servlet.error.request_uri, + * javax.servlet.error.servlet_name. + * @param request current servlet request + */ + public static void clearErrorRequestAttributes(HttpServletRequest request) { + request.removeAttribute(ERROR_STATUS_CODE_ATTRIBUTE); + request.removeAttribute(ERROR_EXCEPTION_TYPE_ATTRIBUTE); + request.removeAttribute(ERROR_MESSAGE_ATTRIBUTE); + request.removeAttribute(ERROR_EXCEPTION_ATTRIBUTE); + request.removeAttribute(ERROR_REQUEST_URI_ATTRIBUTE); + request.removeAttribute(ERROR_SERVLET_NAME_ATTRIBUTE); + } + + /** + * Expose the given Map as request attributes, using the keys as attribute names + * and the values as corresponding attribute values. Keys need to be Strings. + * @param request current HTTP request + * @param attributes the attributes Map + */ + public static void exposeRequestAttributes(ServletRequest request, Map attributes) { + Assert.notNull(request, "Request must not be null"); + Iterator it = attributes.entrySet().iterator(); + while (it.hasNext()) { + Map.Entry entry = (Map.Entry) it.next(); + if (!(entry.getKey() instanceof String)) { + throw new IllegalArgumentException( + "Invalid key [" + entry.getKey() + "] in attributes Map - only Strings allowed as attribute keys"); + } + request.setAttribute((String) entry.getKey(), entry.getValue()); + } + } + + /** + * Retrieve the first cookie with the given name. Note that multiple + * cookies can have the same name but different paths or domains. + * @param request current servlet request + * @param name cookie name + * @return the first cookie with the given name, or null if none is found + */ + public static Cookie getCookie(HttpServletRequest request, String name) { + Assert.notNull(request, "Request must not be null"); + Cookie cookies[] = request.getCookies(); + if (cookies != null) { + for (int i = 0; i < cookies.length; i++) { + if (name.equals(cookies[i].getName())) { + return cookies[i]; + } + } + } + return null; + } + + + /** + * Check if a specific input type="submit" parameter was sent in the request, + * either via a button (directly with name) or via an image (name + ".x" or + * name + ".y"). + * @param request current HTTP request + * @param name name of the parameter + * @return if the parameter was sent + * @see #SUBMIT_IMAGE_SUFFIXES + */ + public static boolean hasSubmitParameter(ServletRequest request, String name) { + Assert.notNull(request, "Request must not be null"); + if (request.getParameter(name) != null) { + return true; + } + for (int i = 0; i < SUBMIT_IMAGE_SUFFIXES.length; i++) { + String suffix = SUBMIT_IMAGE_SUFFIXES[i]; + if (request.getParameter(name + suffix) != null) { + return true; + } + } + return false; + } + + /** + * Obtain a named parameter from the given request parameters. + *

See {@link #findParameterValue(java.util.Map, String)} + * for a description of the lookup algorithm. + * @param request current HTTP request + * @param name the logical name of the request parameter + * @return the value of the parameter, or null + * if the parameter does not exist in given request + */ + public static String findParameterValue(ServletRequest request, String name) { + return findParameterValue(request.getParameterMap(), name); + } + + /** + * Obtain a named parameter from the given request parameters. + *

This method will try to obtain a parameter value using the + * following algorithm: + *

    + *
  1. Try to get the parameter value using just the given logical name. + * This handles parameters of the form logicalName = value. For normal + * parameters, e.g. submitted using a hidden HTML form field, this will return + * the requested value.
  2. + *
  3. Try to obtain the parameter value from the parameter name, where the + * parameter name in the request is of the form logicalName_value = xyz + * with "_" being the configured delimiter. This deals with parameter values + * submitted using an HTML form submit button.
  4. + *
  5. If the value obtained in the previous step has a ".x" or ".y" suffix, + * remove that. This handles cases where the value was submitted using an + * HTML form image button. In this case the parameter in the request would + * actually be of the form logicalName_value.x = 123.
  6. + *
+ * @param parameters the available parameter map + * @param name the logical name of the request parameter + * @return the value of the parameter, or null + * if the parameter does not exist in given request + */ + public static String findParameterValue(Map parameters, String name) { + // First try to get it as a normal name=value parameter + String value = (String) parameters.get(name); + if (value != null) { + return value; + } + // If no value yet, try to get it as a name_value=xyz parameter + String prefix = name + "_"; + Iterator paramNames = parameters.keySet().iterator(); + while (paramNames.hasNext()) { + String paramName = (String) paramNames.next(); + if (paramName.startsWith(prefix)) { + // Support images buttons, which would submit parameters as name_value.x=123 + for (int i = 0; i < SUBMIT_IMAGE_SUFFIXES.length; i++) { + String suffix = SUBMIT_IMAGE_SUFFIXES[i]; + if (paramName.endsWith(suffix)) { + return paramName.substring(prefix.length(), paramName.length() - suffix.length()); + } + } + return paramName.substring(prefix.length()); + } + } + // We couldn't find the parameter value... + return null; + } + + /** + * Return a map containing all parameters with the given prefix. + * Maps single values to String and multiple values to String array. + *

For example, with a prefix of "spring_", "spring_param1" and + * "spring_param2" result in a Map with "param1" and "param2" as keys. + * @param request HTTP request in which to look for parameters + * @param prefix the beginning of parameter names + * (if this is null or the empty string, all parameters will match) + * @return map containing request parameters without the prefix, + * containing either a String or a String array as values + * @see javax.servlet.ServletRequest#getParameterNames + * @see javax.servlet.ServletRequest#getParameterValues + * @see javax.servlet.ServletRequest#getParameterMap + */ + public static Map getParametersStartingWith(ServletRequest request, String prefix) { + Assert.notNull(request, "Request must not be null"); + Enumeration paramNames = request.getParameterNames(); + Map params = new TreeMap(); + if (prefix == null) { + prefix = ""; + } + while (paramNames != null && paramNames.hasMoreElements()) { + String paramName = (String) paramNames.nextElement(); + if ("".equals(prefix) || paramName.startsWith(prefix)) { + String unprefixed = paramName.substring(prefix.length()); + String[] values = request.getParameterValues(paramName); + if (values == null || values.length == 0) { + // Do nothing, no values found at all. + } + else if (values.length > 1) { + params.put(unprefixed, values); + } + else { + params.put(unprefixed, values[0]); + } + } + } + return params; + } + + /** + * Return the target page specified in the request. + * @param request current servlet request + * @param paramPrefix the parameter prefix to check for + * (e.g. "_target" for parameters like "_target1" or "_target2") + * @param currentPage the current page, to be returned as fallback + * if no target page specified + * @return the page specified in the request, or current page if not found + */ + public static int getTargetPage(ServletRequest request, String paramPrefix, int currentPage) { + Enumeration paramNames = request.getParameterNames(); + while (paramNames.hasMoreElements()) { + String paramName = (String) paramNames.nextElement(); + if (paramName.startsWith(paramPrefix)) { + for (int i = 0; i < WebUtils.SUBMIT_IMAGE_SUFFIXES.length; i++) { + String suffix = WebUtils.SUBMIT_IMAGE_SUFFIXES[i]; + if (paramName.endsWith(suffix)) { + paramName = paramName.substring(0, paramName.length() - suffix.length()); + } + } + return Integer.parseInt(paramName.substring(paramPrefix.length())); + } + } + return currentPage; + } + + + /** + * Extract the URL filename from the given request URL path. + * Correctly resolves nested paths such as "/products/view.html" as well. + * @param urlPath the request URL path (e.g. "/index.html") + * @return the extracted URI filename (e.g. "index") + */ + public static String extractFilenameFromUrlPath(String urlPath) { + int end = urlPath.indexOf(';'); + if (end == -1) { + end = urlPath.indexOf('?'); + if (end == -1) { + end = urlPath.length(); + } + } + int begin = urlPath.lastIndexOf('/', end) + 1; + String filename = urlPath.substring(begin, end); + int dotIndex = filename.lastIndexOf('.'); + if (dotIndex != -1) { + filename = filename.substring(0, dotIndex); + } + return filename; + } + +} Index: 3rdParty_sources/spring/org/springframework/web/util/package.html =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/web/util/package.html,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/spring/org/springframework/web/util/package.html 17 Aug 2012 15:16:09 -0000 1.1 @@ -0,0 +1,8 @@ + + + +Miscellaneous web utility classes, such as HTML escaping, +log4j initialization, and cookie handling. + + + Index: 3rdParty_sources/strutstest/servletunit/FilterChainSimulator.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/strutstest/servletunit/Attic/FilterChainSimulator.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/strutstest/servletunit/FilterChainSimulator.java 17 Aug 2012 15:17:08 -0000 1.1 @@ -0,0 +1,88 @@ +// StrutsTestCase - a JUnit extension for testing Struts actions +// within the context of the ActionServlet. +// Copyright (C) 2002 Deryl Seale +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the Apache Software License as +// published by the Apache Software Foundation; either version 1.1 +// of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// Apache Software Foundation Licens for more details. +// +// You may view the full text here: http://www.apache.org/LICENSE.txt + +package servletunit; + +import javax.servlet.FilterChain; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; + +/** + * A unit testing tool for simulating a FilterChain

+ * + * + * @author Sean Pritchard + * May 11, 2002 + * @version 1.0 + */ + +public class FilterChainSimulator implements FilterChain { + + private ServletRequest request = null; + private ServletResponse response = null; + private boolean doFilterCalled = false; + + + /** + * Constructor for the FilterChainSimulator object + */ + public FilterChainSimulator() { } + + + /** + * Description of the Method + * + * @param parm1 The request + * @param parm2 The response + * @exception javax.servlet.ServletException + * @exception java.io.IOException Description of the Exception + */ + public void doFilter(ServletRequest parm1, ServletResponse parm2) throws javax.servlet.ServletException, java.io.IOException { + request = parm1; + response = parm2; + doFilterCalled = true; + } + + + /** + * Gets the request passed in as a parameter of the doFilter call. + * + * @return The request value + */ + public ServletRequest getRequest() { + return request; + } + + + /** + * * Gets the response passed in as a parameter of the doFilter call. + * + * @return The response value + */ + public ServletResponse getResponse() { + return response; + } + + + /** + * Indicates whether doFilter has been called. + * + * @return true if doFilter has been called + */ + public boolean doFilterCalled() { + return doFilterCalled; + } +} Index: 3rdParty_sources/strutstest/servletunit/FilterConfigSimulator.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/strutstest/servletunit/Attic/FilterConfigSimulator.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/strutstest/servletunit/FilterConfigSimulator.java 17 Aug 2012 15:17:08 -0000 1.1 @@ -0,0 +1,103 @@ +// StrutsTestCase - a JUnit extension for testing Struts actions +// within the context of the ActionServlet. +// Copyright (C) 2002 Deryl Seale +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the Apache Software License as +// published by the Apache Software Foundation; either version 1.1 +// of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// Apache Software Foundation Licens for more details. +// +// You may view the full text here: http://www.apache.org/LICENSE.txt + +package servletunit; + +import javax.servlet.FilterConfig; +import javax.servlet.ServletContext; +import java.util.Enumeration; + +// StrutsTestCase - a JUnit extension for testing Struts actions +// within the context of the ActionServlet. +// Copyright (C) 2002 Deryl Seale +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the Apache Software License as +// published by the Apache Software Foundation; either version 1.1 +// of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// Apache Software Foundation Licens for more details. +// +// You may view the full text here: http://www.apache.org/LICENSE.txt + +public class FilterConfigSimulator implements FilterConfig { + + private ServletContext context = null; + + + /** + * Constructor for the FilterConfigSimulator object + * + * @param context The ServletContext to be returned by getServletContext + */ + public FilterConfigSimulator(ServletContext context) { + this.context = context; + } + + + /** + * Gets the filterName attribute of the FilterConfigSimulator object + * + * currently not supported + * + * @return The filterName value + */ + public String getFilterName() { + + throw new java.lang.UnsupportedOperationException("Method getFilterName() not yet implemented."); + } + + + /** + * Gets the initParameter attribute of the FilterConfigSimulator object + * + * currently not supported + * + * @param parm1 Description of the Parameter + * @return The initParameter value + */ + public String getInitParameter(String parm1) { + + throw new java.lang.UnsupportedOperationException("Method getInitParameter() not yet implemented."); + } + + + /** + * Gets the initParameterNames attribute of the FilterConfigSimulator + * object + * + * currently not supported + * + * @return The initParameterNames value + */ + public Enumeration getInitParameterNames() { + + throw new java.lang.UnsupportedOperationException("Method getInitParameterNames() not yet implemented."); + } + + + /** + * Gets the servletContext attribute of the FilterConfigSimulator object + * + * @return The servletContext value + */ + public ServletContext getServletContext() { + return context; + } +} Index: 3rdParty_sources/strutstest/servletunit/HttpServletRequestSimulator.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/strutstest/servletunit/Attic/HttpServletRequestSimulator.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/strutstest/servletunit/HttpServletRequestSimulator.java 17 Aug 2012 15:17:08 -0000 1.1 @@ -0,0 +1,1373 @@ +package servletunit; + +import javax.servlet.RequestDispatcher; +import javax.servlet.ServletContext; +import javax.servlet.ServletInputStream; +import javax.servlet.ServletRequest; +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpSession; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.File; +import java.security.Principal; +import java.util.*; +import java.text.SimpleDateFormat; +import java.text.DateFormat; +import java.text.ParseException; + + +// StrutsTestCase - a JUnit extension for testing Struts actions +// within the context of the ActionServlet. +// Copyright (C) 2002 Deryl Seale +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the Apache Software License as +// published by the Apache Software Foundation; either version 1.1 +// of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// Apache Software Foundation Licens for more details. +// +// You may view the full text here: http://www.apache.org/LICENSE.txt + +public class HttpServletRequestSimulator implements HttpServletRequest +{ + private Hashtable attributes; + private String scheme; + private String protocol = "HTTP/1.1"; + private String requestURI; + private String requestURL; + private String contextPath = ""; + private String servletPath; + private String pathInfo; + private String queryString; + private String method; + private String contentType; + private Locale locale; + private Principal principal; + String remoteAddr; + String localAddr; + String remoteHost; + String localName; + int remotePort; + int localPort; + private String remoteUser; + private String userRole; + private String reqSessionId; + String authType; + String charEncoding; + private String serverName; + private int port; + + private Hashtable parameters; + private Hashtable headers; + private Vector cookies; + + private HttpSession session; + private ServletContext context; + + /** + * Constant used by {@link #setMethod} to indicate that the GET method + * made this request. + */ + + public final static int GET = 0; + + /** + * Constant used by {@link #setMethod} to indicate that the POST method + * made this request. + */ + public final static int POST = 1; + + /** + * Constant used by {@link #setMethod} to indicate that the PUT method + * made this request. + */ + public final static int PUT = 2; + + public HttpServletRequestSimulator(ServletContext context) + { + scheme = "http"; + attributes = new Hashtable(); + parameters = new Hashtable(); + headers = new Hashtable(); + cookies = new Vector(); + this.context = context; + //if (getHeader("Accept")==null) + //setHeader("Accept","dummy accept"); + } + + /** + * Adds a parameter to this object's list of parameters + * + * @param key The name of the parameter + * @param value The value of the parameter + */ + public void addParameter( String key, String value ) + { + if ((key != null) && (value != null)) + this.parameters.put( key, value ); + } + + /** + * Adds a parameter as a String array to this object's list of parameters + */ + public void addParameter(String name, String[] values) { + if ((name != null) && (values != null)) + parameters.put(name,values); + } + + /** + * Returns a java.util.Map of the parameters of this request. + * Request parameters + * are extra information sent with the request. For HTTP servlets, + * parameters are contained in the query string or posted form data. + * + * @return an immutable java.util.Map containing parameter names as + * keys and parameter values as map values. The keys in the parameter + * map are of type String. The values in the parameter map are of type + * String array. + * + */ + public Map getParameterMap() { + return this.parameters; + } + + /** + * + * Returns the value of the named attribute as an Object, + * or null if no attribute of the given name exists. + * + *

Attributes can be set two ways. The servlet container may set + * attributes to make available custom information about a request. + * For example, for requests made using HTTPS, the attribute + * javax.servlet.request.X509Certificate can be used to + * retrieve information on the certificate of the client. Attributes + * can also be set programatically using + * {@link ServletRequest#setAttribute}. This allows information to be + * embedded into a request before a {@link RequestDispatcher} call. + * + *

Attribute names should follow the same conventions as package + * names. This specification reserves names matching java.*, + * javax.*, and sun.*. + * + * @param s a String specifying the name of + * the attribute + * + * @return an Object containing the value + * of the attribute, or null if + * the attribute does not exist + * + */ + public Object getAttribute(String s) + { + return attributes.get(s); + } + + /** + * Returns an Enumeration containing the + * names of the attributes available to this request. + * This method returns an empty Enumeration + * if the request has no attributes available to it. + * + * + * @return an Enumeration of strings + * containing the names + * of the request's attributes + * + */ + public Enumeration getAttributeNames() + { + return attributes.keys(); + } + + /** + * Returns the name of the authentication scheme used to protect + * the servlet. All servlet containers support basic, form and client + * certificate authentication, and may additionally support digest + * authentication. + * If the servlet is not authenticated null is returned. + * + *

Same as the value of the CGI variable AUTH_TYPE. + * + * + * @return one of the static members BASIC_AUTH, + * FORM_AUTH, CLIENT_CERT_AUTH, DIGEST_AUTH + * (suitable for == comparison) + * indicating the authentication scheme, or + * null if the request was + * not authenticated. + * + */ + public String getAuthType() + { + return authType; + } + + /** + * Returns the name of the character encoding used in the body of this + * request. This method returns null if the request + * does not specify a character encoding + * + * + * @return a String containing the name of + * the chararacter encoding, or null + * if the request does not specify a character encoding + */ + public String getCharacterEncoding() + { + return charEncoding; + } + + /** + * Returns the length, in bytes, of the request body + * and made available by the input stream, or -1 if the + * length is not known. For HTTP servlets, same as the value + * of the CGI variable CONTENT_LENGTH. + * + * @return -1, since this is a mock container + */ + public int getContentLength() + { + return -1; + } + + /** + * Returns the MIME type of the body of the request, or + * null if the type is not known. For HTTP servlets, + * same as the value of the CGI variable CONTENT_TYPE. + * + * @return a String containing the name + * of the MIME type of + * the request, or null if the type is not known + * + */ + public String getContentType() + { + return contentType; + } + + /** + * + * Returns the portion of the request URI that indicates the context + * of the request. The context path always comes first in a request + * URI. The path starts with a "/" character but does not end with a "/" + * character. For servlets in the default (root) context, this method + * returns "". The container does not decode this string. + * + * + * @return a String specifying the + * portion of the request URI that indicates the context + * of the request + * + * + */ + public String getContextPath() + { + return contextPath; + } + + /** + * Adds a cookie that can be retrieved from this request via the + * getCookies() method. + * + * @param cookie a Cookie object to be retrieved from this + * request. + * + * @see #getCookies + */ + public void addCookie(Cookie cookie) { + cookies.addElement(cookie); + } + + /** + * Adds a set of cookies that can be retrieved from this request via the + * getCookies() method. + * + * @param cookies an array of Cookie object to be retrieved from this + * request. + * + * @see #getCookies + */ + public void setCookies(Cookie[] cookies) { + for (int i = 0; i < cookies.length; i++) + this.cookies.addElement(cookies[i]); + } + + /** + * + * Returns an array containing all of the Cookie + * objects the client sent with this request. + * This method returns null if no cookies were sent. + * + * @return an array of all the Cookies + * included with this request, or null + * if the request has no cookies + * + * + */ + public Cookie [] getCookies() + { + if (cookies.isEmpty()) + return null; + else { + Cookie[] cookieArray = new Cookie[cookies.size()]; + return (Cookie []) cookies.toArray(cookieArray); + } + } + + /** + * Returns the value of the specified request header as a long value that represents a Date object. Use this + * method with headers that contain dates, such as If-Modified-Since. + *

+ * The date is returned as the number of milliseconds since January 1, 1970 GMT. The header name is case insensitive. + *

+ * If the request did not have a header of the specified name, this method returns -1. If the header can't be converted to a date, the method throws an IllegalArgumentException. + * @param name a String specifying the name of the header + * @return a long value representing the date specified in the header expressed as the number of milliseconds since January 1, 1970 GMT, or -1 if the named header was not included with the reqest. + */ + public long getDateHeader(String name) + { + String s1 = getHeader(name); + if(s1 == null) + return -1L; + try + { + DateFormat dateFormat = new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss z"); + return dateFormat.parse(s1).getTime(); + } + catch(ParseException exception) { + throw new IllegalArgumentException("Cannot parse date: " + s1); + } + } + + /** + * Sets a header with the appropriate date string given the time in milliseconds. + * @param name the name of the header + * @param millis the time in milliseconds + */ + public void setDateHeader(String name, long millis) + { + String dateString = new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss z").format(new Date(millis)); + setHeader(name, dateString); + } + + /** + * + * Returns the value of the specified request header + * as a String. If the request did not include a header + * of the specified name, this method returns null. + * The header name is case insensitive. You can use + * this method with any request header. + * + * @param s a String specifying the + * header name + * + * @return a String containing the + * value of the requested + * header, or null + * if the request does not + * have a header of that name + * + */ + public String getHeader(String s) + { + return (String) headers.get(s); + } + + /** + * + * Returns an enumeration of all the header names + * this request contains. If the request has no + * headers, this method returns an empty enumeration. + * + *

Some servlet containers do not allow do not allow + * servlets to access headers using this method, in + * which case this method returns null + * + * @return an enumeration of all the + * header names sent with this + * request; if the request has + * no headers, an empty enumeration; + * if the servlet container does not + * allow servlets to use this method, + * null + * + * + */ + public Enumeration getHeaderNames() + { + return headers.keys(); + } + + /** + * This operation is not supported. + */ + public Enumeration getHeaders(String s) + { + throw new UnsupportedOperationException("getHeaders operation is not supported!"); + } + + /** + * This operation is not supported. + */ + public ServletInputStream getInputStream() throws IOException { + throw new UnsupportedOperationException("getInputStream operation is not supported!"); + } + + /** + * + * Returns the value of the specified request header + * as an int. If the request does not have a header + * of the specified name, this method returns -1. If the + * header cannot be converted to an integer, this method + * throws a NumberFormatException. + * + *

The header name is case insensitive. + * + * @param s a String specifying the name + * of a request header + * + * @return an integer expressing the value + * of the request header or -1 + * if the request doesn't have a + * header of this name + * + * @exception NumberFormatException If the header value + * can't be converted + * to an int + */ + public int getIntHeader(String s) + { + Object header = headers.get(s); + if (header != null) { + try { + Integer intHeader = (Integer) header; + return intHeader.intValue(); + } catch (ClassCastException e) { + throw new NumberFormatException("header '" + s + "' cannot be converted to number format."); + } + } else + return -1; + } + + /** + * + * Returns the preferred Locale that the client will + * accept content in, based on the Accept-Language header. + * If the client request doesn't provide an Accept-Language header, + * this method returns the default locale for the server. + * + * + * @return the preferred Locale for the client, + * defaults to Locale.US if {@link #setLocale} has + * not been called. + * + */ + public Locale getLocale() + { + if (this.locale == null) + return Locale.US; + else + return this.locale; + } + + /** + * Returns an Enumeration of Locale objects indicating, in decreasing order starting with the preferred locale, the locales that are acceptable to the client based on the Accept-Language header. If the client request doesn't provide an Accept-Language header, this method returns an Enumeration containing one Locale, the default locale for the server. + * @return an Enumeration of preferred Locale objects for the client + */ + + + + public Enumeration getLocales() + { + return java.util.Collections.enumeration(Collections.singleton(getLocale())); + } + + /** + * + * Returns the name of the HTTP method with which this + * request was made, for example, GET, POST, or PUT. + * Same as the value of the CGI variable REQUEST_METHOD. + * + * @return a String + * specifying the name + * of the method with which + * this request was made + * + */ + public String getMethod() + { + if (method == null) + return "POST"; + else + return method; + } + + /** + * Returns the value of a request parameter as a String, + * or null if the parameter does not exist. Request parameters + * are extra information sent with the request. For HTTP servlets, + * parameters are contained in the query string or posted form data. + * + *

You should only use this method when you are sure the + * parameter has only one value. If the parameter might have + * more than one value, use {@link #getParameterValues}. + * + *

If you use this method with a multivalued + * parameter, the value returned is equal to the first value + * in the array returned by getParameterValues. + * + *

If the parameter data was sent in the request body, such as occurs + * with an HTTP POST request, then reading the body directly via {@link + * #getInputStream} or {@link #getReader} can interfere + * with the execution of this method. + * + * @param s a String specifying the + * name of the parameter + * + * @return a String representing the + * single value of the parameter + * + * @see #getParameterValues + * + */ + public String getParameter( String s ) + { + if (s == null) + return null; + + Object param = parameters.get(s); + if( null == param ) + return null; + if( param.getClass().isArray() ) + return ((String[]) param)[0]; + return (String)param; + } + + /** + * + * Returns an Enumeration of String + * objects containing the names of the parameters contained + * in this request. If the request has + * no parameters, the method returns an + * empty Enumeration. + * + * @return an Enumeration of String + * objects, each String containing + * the name of a request parameter; or an + * empty Enumeration if the + * request has no parameters + * + */ + public Enumeration getParameterNames() + { + return parameters.keys(); + } + + /** + * Returns an array of String objects containing + * all of the values the given request parameter has, or + * null if the parameter does not exist. + * + *

If the parameter has a single value, the array has a length + * of 1. + * + * @param s a String containing the name of + * the parameter whose value is requested + * + * @return an array of String objects + * containing the parameter's values + * + * @see #getParameter + * + */ + public String[] getParameterValues( String s ) + { + if (s == null) + return null; + Object param = parameters.get( s ); + if( null == param ) + return null; + else { + if (param.getClass().isArray()) { + return (String[]) param; + } else { + return new String[] {(String) param}; + } + } + } + + /** + * + * Returns any extra path information associated with + * the URL the client sent when it made this request. + * The extra path information follows the servlet path + * but precedes the query string. + * This method returns null if there + * was no extra path information. + * + *

Same as the value of the CGI variable PATH_INFO. + * + * + * @return a String, decoded by the + * web container, specifying + * extra path information that comes + * after the servlet path but before + * the query string in the request URL; + * or null if the URL does not have + * any extra path information + * + */ + public String getPathInfo() + { + return pathInfo; + } + + /** + * This operation is not supported. + */ + public String getPathTranslated() + { + throw new UnsupportedOperationException("getPathTranslated operation is not supported!"); + } + + /** + * Returns the name and version of the protocol the request uses + * in the form protocol/majorVersion.minorVersion, for + * example, HTTP/1.1. For HTTP servlets, the value + * returned is the same as the value of the CGI variable + * SERVER_PROTOCOL. + * + * @return a String containing the protocol + * name and version number + * + */ + public String getProtocol() + { + return protocol; + } + + /** + * + * Returns the query string that is contained in the request + * URL after the path. This method returns null + * if the URL does not have a query string. Same as the value + * of the CGI variable QUERY_STRING. + * + * @return a String containing the query + * string or null if the URL + * contains no query string. The value is not + * decoded by the container. + * + */ + public String getQueryString() + { + return queryString; + } + + /** + * This operation is not supported. + */ + public BufferedReader getReader() throws IOException { + throw new UnsupportedOperationException("getReader operation is not supported!"); + } + + /** + * + * @deprecated As of Version 2.1 of the Java Servlet API, + * use {@link ServletContext#getRealPath} instead. + * + */ + public String getRealPath(String path) + { + File contextDirectory = ((ServletContextSimulator) context).getContextDirectory(); + if ((contextDirectory == null) || (path == null)) + return null; + else + return (new File(contextDirectory, path)).getAbsolutePath(); + } + + /** + * Returns the Internet Protocol (IP) address of the client + * that sent the request. For HTTP servlets, same as the value of the + * CGI variable REMOTE_ADDR. + * + * @return a String containing the + * IP address of the client that sent the request + * + */ + public String getRemoteAddr() { + return remoteAddr; + } + + /** + * Returns the fully qualified name of the client that sent the + * request. If the engine cannot or chooses not to resolve the hostname + * (to improve performance), this method returns the dotted-string form of + * the IP address. For HTTP servlets, same as the value of the CGI variable + * REMOTE_HOST. + * + * @return a String containing the fully + * qualified name of the client + * + */ + public String getRemoteHost() { + return remoteHost; + } + + /** + * Returns the fully qualified name of the client that sent the + * request. If the engine cannot or chooses not to resolve the hostname + * (to improve performance), this method returns the dotted-string form of + * the IP address. For HTTP servlets, same as the value of the CGI variable + * REMOTE_HOST. + * + * @return a String containing the fully + * qualified name of the client + * + */ + public String getRemoteUser() + { + return remoteUser; + } + + /** + * + * Returns a {@link RequestDispatcher} object that acts as a wrapper for + * the resource located at the given path. + * A RequestDispatcher object can be used to forward + * a request to the resource or to include the resource in a response. + * The resource can be dynamic or static. + * + *

The pathname specified may be relative, although it cannot extend + * outside the current servlet context. If the path begins with + * a "/" it is interpreted as relative to the current context root. + * This method returns null if the servlet container + * cannot return a RequestDispatcher. + * + *

The difference between this method and {@link + * ServletContext#getRequestDispatcher} is that this method can take a + * relative path. + * + * @param url a String specifying the pathname + * to the resource + * + * @return a RequestDispatcher object + * that acts as a wrapper for the resource + * at the specified path + * + * @see RequestDispatcherSimulator + * @see ServletContextSimulator#getRequestDispatcher + * + */ + public RequestDispatcher getRequestDispatcher( String url ) + { + return context.getRequestDispatcher(url); + } + + /** + * + * Returns the session ID specified by the client. This may + * not be the same as the ID of the actual session in use. + * For example, if the request specified an old (expired) + * session ID and the server has started a new session, this + * method gets a new session with a new ID. If the request + * did not specify a session ID, this method returns + * null. + * + * + * @return a String specifying the session + * ID, or null if the request did + * not specify a session ID + * + * @see #isRequestedSessionIdValid + * + */ + public String getRequestedSessionId() + { + return reqSessionId; + } + + /** + * + * Returns the part of this request's URL from the protocol + * name up to the query string in the first line of the HTTP request. + * The web container does not decode this String. + * For example: + * + * + * + * + * + *
First line of HTTP request Returned Value
POST /some/path.html HTTP/1.1/some/path.html + *
GET http://foo.bar/a.html HTTP/1.0 + * /a.html + *
HEAD /xyz?a=b HTTP/1.1/xyz + *
+ * + * + * @return a String containing + * the part of the URL from the + * protocol name up to the query string + * + * + */ + public String getRequestURI() + { + return requestURI; + } + + + /** + * Reconstructs the URL the client used to make the request. The returned URL contains a protocol, server name, port number, and server path, but it does not include query string parameters. + *

+ * Because this method returns a StringBuffer, not a string, you can modify the URL easily, for example, to append query parameters. + *

+ * This method is useful for creating redirect messages and for reporting errors. + * @return a StringBuffer object containing the reconstructed URL + */ + + public StringBuffer getRequestURL() + { + return new StringBuffer(requestURL); + } + + /** + * Returns the name of the scheme used to make this request, + * for example, + * http, https, or ftp. + * Different schemes have different rules for constructing URLs, + * as noted in RFC 1738. + * + * @return a String containing the name + * of the scheme used to make this request + * + */ + public String getScheme() + { + return scheme; + } + + /** + * Returns the host name of the server that received + * the request. For HTTP servlets, same as the value of + * the CGI variable SERVER_NAME. + * @return the name of the server to which the request was sent + */ + public String getServerName() { + return serverName; + } + + /** + * Returns the port number on which this request was received. For HTTP servlets, same as the value of the CGI variable SERVER_PORT. + * @return an integer specifying the port number + */ + public int getServerPort() { + return this.port; + } + + /** + * Sets the server port to be used with {@link#getServerPort}. + */ + public void setServerPort(int port) { + this.port = port; + } + + /** + * + * Returns the part of this request's URL that calls + * the servlet. This includes either the servlet name or + * a path to the servlet, but does not include any extra + * path information or a query string. Same as the value + * of the CGI variable SCRIPT_NAME. + * + * + * @return a String containing + * the name or path of the servlet being + * called, as specified in the request URL, + * decoded. + * + * + */ + public String getServletPath() + { + return servletPath; + } + + /** + * + * Returns the current session associated with this request, + * or if the request does not have a session, creates one. + * + * @return the HttpSession associated + * with this request + * + * @see #getSession(boolean) + * + */ + public HttpSession getSession() + { + return getSession(true); + } + + /** + * + * Returns the current HttpSession + * associated with this request or, if if there is no + * current session and create is true, returns + * a new session. + * + *

If create is false + * and the request has no valid HttpSession, + * this method returns null. + * + *

To make sure the session is properly maintained, + * you must call this method before + * the response is committed. If the container is using cookies + * to maintain session integrity and is asked to create a new session + * when the response is committed, an IllegalStateException is thrown. + * + * + * + * + * @param b true to create + * a new session for this request if necessary; + * false to return null + * if there's no current session + * + * + * @return the HttpSession associated + * with this request or null if + * create is false + * and the request has no valid session + * + * @see #getSession() + * + * + */ + public HttpSession getSession(boolean b) + { + if ((session == null) && (b)) + this.session = new HttpSessionSimulator(context); + else if ((session != null) && (!((HttpSessionSimulator) session).isValid()) && (b)) + this.session = new HttpSessionSimulator(context); + if ((session != null) && (((HttpSessionSimulator) session).isValid())) + return this.session; + else + return null; + } + + /** + * + * Returns a java.security.Principal object containing + * the name of the current authenticated user. If the user has not been + * authenticated, the method returns null. + * + * @return a java.security.Principal containing + * the name of the user making this request; + * null if the user has not been + * authenticated + * + */ + public Principal getUserPrincipal() + { + return this.principal; + } + + /** + * + * Checks whether the requested session ID came in as a cookie. + * + * @return true in all cases + * + * @see #getSession + * + */ + public boolean isRequestedSessionIdFromCookie() + { + return true; + } + + /** + * + * @deprecated As of Version 2.1 of the Java Servlet + * API, use {@link #isRequestedSessionIdFromURL} + * instead. + * + */ + public boolean isRequestedSessionIdFromUrl() + { + return isRequestedSessionIdFromURL(); + } + + /** + * + * Checks whether the requested session ID came in as part of the + * request URL. + * + * @return false in all cases. + * + * @see #getSession + * + */ + public boolean isRequestedSessionIdFromURL() + { + return false; + } + + /** + * + * Checks whether the requested session ID is still valid. + * + * @return true if this + * request has an id for a valid session + * in the current session context; + * false otherwise + * + * @see #getRequestedSessionId + * @see #getSession + * + */ + public boolean isRequestedSessionIdValid() + { + if (session != null) { + try { + session.getId(); + return true; + } catch (IllegalStateException e) { + return false; + } + } else + return false; + } + + /** + * + * Returns a boolean indicating whether this request was made using a + * secure channel, such as HTTPS. + * + * + * @return true if scheme has been set to HTTPS (ignoring case) + * + */ + public boolean isSecure() + { + if(scheme==null){ + return false; + } else{ + return scheme.equalsIgnoreCase("HTTPS"); + } + } + + /** + * + * Returns a boolean indicating whether the authenticated user is included + * in the specified logical "role". Roles and role membership can be + * defined using deployment descriptors. If the user has not been + * authenticated, the method returns false. + * + * @param s a String specifying the name + * of the role + * + * @return false in all cases + * + */ + public boolean isUserInRole(String s) + { + return s.equals(userRole); + } + + /** + * Sets user role to be used in {@link #isUserInRole} + */ + public void setUserRole(String role) { + this.userRole = role; + } + + /** + * + * Removes an attribute from this request. This method is not + * generally needed as attributes only persist as long as the request + * is being handled. + * + *

Attribute names should follow the same conventions as + * package names. Names beginning with java.*, + * javax.*, and com.sun.*, are + * reserved for use by Sun Microsystems. + * + * + * @param s a String specifying + * the name of the attribute to remove + * + */ + public void removeAttribute(String s) + { + attributes.remove(s); + } + + /** + * + * Stores an attribute in this request. + * Attributes are reset between requests. This method is most + * often used in conjunction with {@link RequestDispatcher}. + * + *

Attribute names should follow the same conventions as + * package names. Names beginning with java.*, + * javax.*, and com.sun.*, are + * reserved for use by Sun Microsystems. + *
If the value passed in is null, the effect is the same as + * calling {@link #removeAttribute}. + * + * + * + * @param name a String specifying + * the name of the attribute + * + * @param o the Object to be stored + * + */ + public void setAttribute(String name, Object o) + { + if (o == null) + attributes.remove(name); + else + attributes.put(name, o); + } + + + /** + * Sets authentication scheme to be used in {@link #getAuthType}. + */ + public void setAuthType(String s) + { + authType = s; + } + + /** + * Sets character encoding to be used in {@link #getCharacterEncoding}. + */ + public void setCharacterEncoding(String s) + { + charEncoding = s; + } + + /** + * Sets content type to be used in {@link #getContentType}. + */ + public void setContentType(String s) { + contentType = s; + } + + /** + * Sets a header to be used in {@link #getHeader}. + */ + public void setHeader(String key, String value) + { + headers.put(key,value); + } + + /** + * Sets the name of the HTTP method with which this request + * was made. This value will be returned in the getMethod + * method. + * + * + * @param methodType one of the following constant values + * defined in this class: {@link #GET}, {@link #POST}, and {@link #PUT} + * + */ + public void setMethod(int methodType) + { + switch (methodType) + { + case GET:method="GET";break; + case PUT:method="PUT";break; + case POST:method="POST";break; + default:method="POST"; + } + } + + /** + * Sets parameter value to be used by {@link #getParameter}. + */ + public void setParameterValue( String key, String[] value ) + { + parameters.put( key, value ); + } + + /** + * Sets path information to be used by {@link #getPathInfo}. + */ + public void setPathInfo(String s) + { + pathInfo = s; + } + + /** + * Sets query string to be used by {@link #getQueryString}. + */ + public void setQueryString(String s) { + this.queryString = s; + } + + /** + * Sets remote user to be used by {@link #getRemoteUser}. + */ + public void setRemoteUser(String remoteUser) + { + this.remoteUser = remoteUser; + } + + /** + * Sets remote address to be used by {@link #getRemoteAddr}. + */ + public void setRemoteAddr(String remoteAddr) { + this.remoteAddr = remoteAddr; + } + + /** + * Sets remote host to be used by {@link #getRemoteHost}. + */ + public void setRemoteHost(String remoteHost) { + this.remoteHost = remoteHost; + } + + /** + * Sets requested session ID to be used by {@link #getRequestedSessionId}. + */ + public void setRequestedSessionId(String s) + { + reqSessionId = s; + } + + /** + * Sets request URI to be used by {@link #getRequestURI}. + */ + public void setRequestURI(String requestURI) + { + this.requestURI = requestURI; + } + + /** + * Sets the request URL to be used in this test. This method uses + * the given request URL to also set the scheme, server name, server + * port, request URI, and query string. + */ + public void setRequestURL(String url) { + + // set request url + int queryIndex = url.lastIndexOf('?'); + if (queryIndex < 0) + queryIndex = url.length(); + this.requestURL = url.substring(0,queryIndex); + + // set query string + if (queryIndex != url.length()) + setQueryString(url.substring(queryIndex + 1)); + + // set scheme + int schemeIndex = url.lastIndexOf("://"); + setScheme(url.substring(0,schemeIndex)); + + // set uri + setRequestURI(url.substring(url.indexOf('/',schemeIndex + 3),queryIndex)); + + // set server name and port + int portIndex = url.indexOf(':',schemeIndex + 2); + if (portIndex > 0) { + setServerName(url.substring(schemeIndex + 3, portIndex)); + setServerPort(Integer.parseInt(url.substring(portIndex + 1,url.indexOf('/',schemeIndex + 3)))); + } else { + setServerName(url.substring(schemeIndex + 3,url.indexOf('/',schemeIndex + 3))); + if (isSecure()) + setServerPort(443); + else + setServerPort(80); + } + } + + /** + * Sets scheme to be used by {@link #getScheme}. + */ + public void setScheme(String s) + { + scheme = s; + } + + /** + * Sets servlet path to be used by {@link #getServletPath}. + */ + public void setServletPath(String s) + { + servletPath = s; + } + + /** + * Sets server name to be used by {@link #getServerName}. + */ + public void setServerName(String s) + { + serverName = s; + } + + /** + * Sets the context path to be used by {@link #getContextPath}. + */ + public void setContextPath(String s) + { + contextPath = s; + } + + + /** + * Sets the locale to be used by {@link #getLocale}. + */ + public void setLocale(Locale locale) { + this.locale = locale; + } + + /** + * Sets the Principal used by {@link #getUserPrincipal}. + */ + public void setUserPrincipal(Principal principal) { + this.principal = principal; + } + + public int getRemotePort() { + return remotePort; + } + + public void setRemotePort(int remotePort) { + this.remotePort = remotePort; + } + + public String getLocalAddr() { + return localAddr; + } + + public void setLocalAddr(String localAddr) { + this.localAddr = localAddr; + } + + public String getLocalName() { + return localName; + } + + public void setLocalName(String localName) { + this.localName = localName; + } + + public int getLocalPort() { + return localPort; + } + + public void setLocalPort(int localPort) { + this.localPort = localPort; + } + + +} Index: 3rdParty_sources/strutstest/servletunit/HttpServletResponseSimulator.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/strutstest/servletunit/Attic/HttpServletResponseSimulator.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/strutstest/servletunit/HttpServletResponseSimulator.java 17 Aug 2012 15:17:08 -0000 1.1 @@ -0,0 +1,649 @@ +package servletunit; + +// ServletUnit Library v1.2 - A java-based testing framework for servlets +// Copyright (C) June 1, 2001 Somik Raha +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// For any questions or suggestions, you can write to me at : +// Email : somik@kizna.com +// +// Postal Address : +// Somik Raha +// R&D Team +// Kizna Corporation +// 2-1-17-6F, Sakamoto Bldg., Moto Azabu, Minato ku, Tokyo, 106 0046, JAPAN +// +// Additions by: +// +// Dane S. Foster +// Equity Technology Group, Inc +// http://www.equitytg.com. +// 954.360.9800 +// dfoster@equitytg.com +// +// Additions by: +// Sean Pritchard +// smpritchard@yahoo.com +// +import junit.framework.AssertionFailedError; + +import javax.servlet.ServletOutputStream; +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServletResponse; +import java.io.*; +import java.util.HashMap; +import java.util.Locale; +import java.util.Date; +import java.text.SimpleDateFormat; + + +// StrutsTestCase - a JUnit extension for testing Struts actions +// within the context of the ActionServlet. +// Copyright (C) 2002 Deryl Seale +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the Apache Software License as +// published by the Apache Software Foundation; either version 1.1 +// of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// Apache Software Foundation Licens for more details. +// +// You may view the full text here: http://www.apache.org/LICENSE.txt + +public class HttpServletResponseSimulator implements HttpServletResponse +{ + private OutputStream servOStream; // The non-default javax.servlet.ServletOutputStream + + private boolean calledGetWriter, calledGetOutputStream; + private StringWriter stringWriter=null; + private PrintWriter printWriter=null; + private Locale locale = null; + private int contentLength; + private String contentType = null; + private int status = 200; + private String message = null; + private HashMap headers = new HashMap(); + private HashMap cookies = new HashMap(); + + String charEncoding; + + private boolean isCommitted = false; + + public static final int SC_CONTINUE = 100; + + + public static final int SC_SWITCHING_PROTOCOLS = 101; + + public static final int SC_OK = 200; + + public static final int SC_CREATED = 201; + + public static final int SC_ACCEPTED = 202; + + public static final int SC_NON_AUTHORITATIVE_INFORMATION = 203; + + public static final int SC_NO_CONTENT = 204; + + public static final int SC_RESET_CONTENT = 205; + + public static final int SC_PARTIAL_CONTENT = 206; + + public static final int SC_MULTIPLE_CHOICES = 300; + + public static final int SC_MOVED_PERMANENTLY = 301; + + public static final int SC_MOVED_TEMPORARILY = 302; + + public static final int SC_SEE_OTHER = 303; + + public static final int SC_NOT_MODIFIED = 304; + + public static final int SC_USE_PROXY = 305; + + public static final int SC_BAD_REQUEST = 400; + + public static final int SC_UNAUTHORIZED = 401; + + public static final int SC_PAYMENT_REQUIRED = 402; + + public static final int SC_FORBIDDEN = 403; + + public static final int SC_NOT_FOUND = 404; + + public static final int SC_METHOD_NOT_ALLOWED = 405; + + public static final int SC_NOT_ACCEPTABLE = 406; + + public static final int SC_PROXY_AUTHENTICATION_REQUIRED = 407; + + public static final int SC_REQUEST_TIMEOUT = 408; + + public static final int SC_CONFLICT = 409; + + public static final int SC_GONE = 410; + + public static final int SC_LENGTH_REQUIRED = 411; + + public static final int SC_PRECONDITION_FAILED = 412; + + public static final int SC_REQUEST_ENTITY_TOO_LARGE = 413; + + public static final int SC_REQUEST_URI_TOO_LONG = 414; + + public static final int SC_UNSUPPORTED_MEDIA_TYPE = 415; + + public static final int SC_REQUESTED_RANGE_NOT_SATISFIABLE = 416; + + public static final int SC_EXPECTATION_FAILED = 417; + + public static final int SC_INTERNAL_SERVER_ERROR = 500; + + public static final int SC_NOT_IMPLEMENTED = 501; + + public static final int SC_BAD_GATEWAY = 502; + + public static final int SC_SERVICE_UNAVAILABLE = 503; + + public static final int SC_GATEWAY_TIMEOUT = 504; + + public static final int SC_HTTP_VERSION_NOT_SUPPORTED = 505; + + /** + * Add a cookie to this response, which will then be stored in the browser. + */ + public void addCookie(Cookie cookie) + { + cookies.put( cookie.getName(), cookie ); + } + + /** + * Returns a cookie with a given, or null if this cookie has + * not been added to the repsonse. + */ + public Cookie findCookie( String name ) { + return (Cookie) cookies.get( name ); + } + + /** + * This method is not supported. + */ + public void addDateHeader(String name, long date) + { + this.headers.put(name,new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss z").format(new Date(date))); + } + + /** + * Adds a response header with the given name and value. + */ + public void addHeader(String name, String value) + { + this.setHeader(name,value); + } + + /** + * Returns a given header field, or null if this header + * has not been set. + */ + public String getHeader(String name) { + if (headers.containsKey(name)) + return (String) headers.get(name); + else + return null; + } + + /** + * Adds a response header with the given name and integer value. + */ + public void addIntHeader(String name, int value) + { + this.setIntHeader(name,value); + } + + /** + * returns true if a header with the given name + * has already been set + */ + public boolean containsHeader(String name) + { + return headers.containsKey(name); + } + + /** + * Returns the given URL unmodified + */ + public String encodeRedirectUrl(String url) + { + return url; + } + + + /** + * Returns the given URL unmodified. + */ + public String encodeRedirectURL(String url) + { + return url; + } + + /** + * Returns the given URL unmodified. + */ + public String encodeUrl(String url) + { + return url; + } + + /** + * Returns the given URL unmodified + */ + public String encodeURL(String url) + { + return url; + } + + /** + * This method is not supported. + */ + public void flushBuffer() throws IOException + { + throw new UnsupportedOperationException("flushBuffer operation is not supported!"); + } + + + /** + * This method is not supported. + */ + public int getBufferSize() + { + throw new UnsupportedOperationException("getBufferSize operation is not supported!"); + } + + /** + * This method is not supported. + */ + public String getCharacterEncoding() + { + return charEncoding; + } + + /** + * Returns the locale assigned to the response. + * + * + * @see #setLocale + * + */ + public Locale getLocale() + { + if (locale == null) + return Locale.US; + else + return locale; + } + + + + /** + * Returns a {@link ServletOutputStream} suitable for writing binary + * data in the response. The servlet container does not encode the + * binary data. + + *

Calling flush() on the ServletOutputStream commits the response. + + * Either this method or {@link #getWriter} may + * be called to write the body, not both. + * + * @return a {@link ServletOutputStream} for writing binary data + * + * @exception IllegalStateException if the getWriter method + * has been called on this response + * + * @exception IOException if an input or output exception occurred + * + * @see #getWriter + * + */ + public ServletOutputStream getOutputStream() throws IOException + { + if( this.calledGetWriter ) + throw new IllegalStateException( "The getWriter method has already been called" ); + + ServletOutputStream oStream = null; + if( null == this.servOStream ) + oStream = new ServletOutputStreamSimulator(); + else + oStream = new ServletOutputStreamSimulator( this.servOStream ); + // resets the status of servOStream to prevent us from possible using a closed stream + this.servOStream = null; + this.calledGetOutputStream = true; + return oStream; + } + + + /** + * Returns a PrintWriter object that + * can send character text to the client. + * The character encoding used is the one specified + * in the charset= property of the + * {@link #setContentType} method, which must be called + * before calling this method for the charset to take effect. + * + *

If necessary, the MIME type of the response is + * modified to reflect the character encoding used. + * + *

Calling flush() on the PrintWriter commits the response. + * + *

Either this method or {@link #getOutputStream} may be called + * to write the body, not both. + * + * + * @return a PrintWriter object that + * can return character data to the client + * + * @exception UnsupportedEncodingException if the charset specified in + * setContentType cannot be + * used + * + * @exception IllegalStateException if the getOutputStream + * method has already been called for this + * response object + * + * @exception IOException if an input or output exception occurred + * + * @see #getOutputStream + * @see #setContentType + * + */ + public PrintWriter getWriter() throws IOException + { + if( this.calledGetOutputStream ) + throw new IllegalStateException( "The getOutputStream method has already been called" ); + + if( stringWriter == null ) + stringWriter = new StringWriter(); + if( printWriter == null ) + printWriter = new PrintWriter( stringWriter ); + + this.calledGetWriter = true; + return printWriter; + } + + + /** + * Use this method to pick up the string buffer which will hold + * the contents of the string buffer. You can then + * write your test case to examine the contents of this + * buffer and match it against an expected output. + */ + public StringBuffer getWriterBuffer() + { + if (stringWriter==null) return null; + return stringWriter.getBuffer(); + } + + //TODO: better documentation + public boolean isCommitted() + { + return isCommitted; + } + + public void setIsCommitted(boolean isCommitted) { + this.isCommitted = isCommitted; + } + + /** + * Reinitializes all local variables. + * Note, in most servlet containers, you may get an + * IllegalStateException if you call this method + * after committing the response. + * That behavior is not replicated here. + */ + public void reset() + { + this.calledGetOutputStream = false; + this.calledGetWriter = false; + this.contentLength = 0; + this.contentType = null; + this.stringWriter = null; + this.printWriter = null; + headers = new HashMap(); + } + + /** + * This method is not supported. + */ + public void resetBuffer() + { + throw new UnsupportedOperationException("resetBuffer operation is not supported."); + } + + /** + * Sends an error response to the client using the specified + * status clearing the buffer. This method always throws + * an AssertionFailedError with the corresponding error + * number. + * + * @param sc the error status code + */ + public void sendError(int sc) throws IOException + { + setStatus(sc); + throw new AssertionFailedError("received error: " + sc); + } + + + /** + * Sends an error response to the client using the specified + * status clearing the buffer. This method always throws + * an AssertionFailedError with the corresponding error + * number and descriptive text. + * + * @param sc the error status code + * @param msg the descriptive message + */ + public void sendError(int sc, String msg) throws IOException + { + setStatus(sc,msg); + throw new AssertionFailedError("received error " + sc + " : " + msg); + } + + /** + * Resets the response and sets the appropriate redirect headers. + */ + public void sendRedirect(String location) throws IOException + { + reset(); + setStatus(SC_MOVED_TEMPORARILY); + setHeader("Location", location); + } + + /** + * This method is not supported. + */ + public void setBufferSize(int size) + { + throw new UnsupportedOperationException("setBufferSize operation not supported."); + } + + + /** + * Sets the length of the content body in the response + * In HTTP servlets, this method sets the HTTP Content-Length header. + * + * + * @param len an integer specifying the length of the + * content being returned to the client; sets + * the Content-Length header + * + */ + public void setContentLength(int len) + { + this.contentLength = len; + } + + /** + * returns the content length previously set in setContentLength() + * @return the content length + */ + public int getContentLength(){ + return this.contentLength; + } + + /** + * Sets the content type of the response being sent to + * the client. The content type may include the type of character + * encoding used, for example, text/html; charset=ISO-8859-4. + * + *

If obtaining a PrintWriter, this method should be + * called first. + * + * + * @param type a String specifying the MIME + * type of the content + * + * @see #getOutputStream + * @see #getWriter + * + */ + public void setContentType(String type) + { + this.contentType = type; + } + + /** + * returns the content type previously set in setContentType() + * @return the content type + */ + public String getContentType(){ + return this.contentType; + } + + + /** + * This method is not supported. + */ + public void setDateHeader(String name, long date) + { + this.addDateHeader(name,date); + } + + /** + * adds the name/value pair to the headers + */ + public void setHeader(String name, String value) + { + if (name.equalsIgnoreCase("content-type")) { + setContentType(value); + return; + } + else if (name.equalsIgnoreCase("content-length")) { + this.setContentLength(Integer.parseInt(value)); + return; + } + + headers.put(name, value); + } + + /** + * Removes a given header + */ + public void removeHeader(String name) { + if (headers.containsKey(name)) + headers.remove(name); + } + + /** + * Adds the given name/value pair to the headers collection. + */ + public void setIntHeader(String name, int value) + { + setHeader(name, String.valueOf(value)); + } + + + /** + * Sets the locale of the response, setting the headers (including the + * Content-Type's charset) as appropriate. This method should be called + * before a call to {@link #getWriter}. By default, the response locale + * is the default locale for the server. + * + * @param loc the locale of the response + * + * @see #getLocale + * + */ + public void setLocale(Locale loc) + { + this.locale = loc; + } + + /** + * The default action of calling the getOutputStream method + * is to return a javax.servlet.ServletOutputStream object + * that sends the data to System.out. If you don't want + * the output sent to System.out you can use this method to + * set where the output will go. Please note, subsequent calls to + * getOutputStream will reset the output path to + * System.out. This prevents the OutputStream returned by + * calling getOutputStream from writing to a closed stream + * + * @param out The java.io.OutputStream that represents + * the real path of the output. + */ + public void setOutputStream( OutputStream out ) + { + this.servOStream = out; + } + + /** + * Sets the given status code. + */ + public void setStatus(int sc) + { + setStatus(sc, null); + } + + /** + * Sets the given status and an associated message. + */ + public void setStatus(int sc, String sm) + { + this.status = sc; + this.message = sm; + } + + /** + * Returns the status code for this response, which is useful for testing expected errors. + * @return the status code for this response. + */ + public int getStatusCode() { + return this.status; + } + + public void setCharacterEncoding(String charEncoding) { + this.charEncoding = charEncoding; + } + + public String getMessage() { + return message; + } + + +} + Index: 3rdParty_sources/strutstest/servletunit/HttpSessionSimulator.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/strutstest/servletunit/Attic/HttpSessionSimulator.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/strutstest/servletunit/HttpSessionSimulator.java 17 Aug 2012 15:17:08 -0000 1.1 @@ -0,0 +1,150 @@ +package servletunit; + +import javax.servlet.ServletContext; +import javax.servlet.http.HttpSession; +import javax.servlet.http.HttpSessionContext; +import java.util.Enumeration; +import java.util.Hashtable; + +// StrutsTestCase - a JUnit extension for testing Struts actions +// within the context of the ActionServlet. +// Copyright (C) 2002 Deryl Seale +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the Apache Software License as +// published by the Apache Software Foundation; either version 1.1 +// of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// Apache Software Foundation Licens for more details. +// +// You may view the full text here: http://www.apache.org/LICENSE.txt + +/** + * This class simulates an HttpSession object. You can actually work with sessions. The simulation is done using a static + * session object inside HttpServletRequest. + */ +public class HttpSessionSimulator implements HttpSession +{ + private Hashtable values; + private boolean valid = true; + private ServletContext context; + + public HttpSessionSimulator(ServletContext context) + { + this.context = context; + values = new Hashtable(); + } + + public Object getAttribute(String s) throws IllegalStateException + { + checkValid(); + return values.get(s); + } + + public Enumeration getAttributeNames() throws IllegalStateException + { + checkValid(); + return values.keys(); + } + + public long getCreationTime() throws IllegalStateException + { + checkValid(); + return -1; + } + + public String getId() + { + return "-9999"; + } + + public long getLastAccessedTime() + { + return -1; + } + + public int getMaxInactiveInterval() throws IllegalStateException + { + checkValid(); + return -1; + } + + /** + * This method is not supported. + */ + public HttpSessionContext getSessionContext() + { + throw new UnsupportedOperationException("getSessionContext not supported!"); + } + + public Object getValue(String s) throws IllegalStateException + { + checkValid(); + return values.get(s); + } + + public String[] getValueNames() throws IllegalStateException + { + checkValid(); + return (String[]) values.keySet().toArray(); + } + + public void invalidate() throws IllegalStateException + { + checkValid(); + this.valid = false; + } + + public boolean isNew() throws IllegalStateException + { + checkValid(); + return false; + } + + public void putValue(String s, Object obj) throws IllegalStateException + { + checkValid(); + values.put(s,obj); + } + + public void removeAttribute(String s) throws IllegalStateException + { + checkValid(); + values.remove(s); + } + + public void removeValue(String s) throws IllegalStateException + { + checkValid(); + values.remove(s); + } + + public void setAttribute(String s, Object obj) throws IllegalStateException + { + checkValid(); + if (obj == null) + removeValue(s); + else + values.put(s,obj); + } + + public void setMaxInactiveInterval(int i) + { + } + + public ServletContext getServletContext() { + return this.context; + } + + private void checkValid() throws IllegalStateException { + if (!valid) + throw new IllegalStateException("session has been invalidated!"); + } + + protected boolean isValid() { + return valid; + } +} Index: 3rdParty_sources/strutstest/servletunit/RequestDispatcherSimulator.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/strutstest/servletunit/Attic/RequestDispatcherSimulator.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/strutstest/servletunit/RequestDispatcherSimulator.java 17 Aug 2012 15:17:08 -0000 1.1 @@ -0,0 +1,60 @@ +package servletunit; + +// StrutsTestCase - a JUnit extension for testing Struts actions +// within the context of the ActionServlet. +// Copyright (C) 2002 Deryl Seale +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the Apache Software License as +// published by the Apache Software Foundation; either version 1.1 +// of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// Apache Software Foundation Licens for more details. +// +// You may view the full text here: http://www.apache.org/LICENSE.txt + +import javax.servlet.*; +import java.io.IOException; + +/** + * Simulates a javax.servlet.RequestDispatcher object. + */ +public class RequestDispatcherSimulator implements RequestDispatcher +{ + private Object dispatchedResource; + /** + *@param dispatchedResource The dispatchedResource object represents the resource that + * this javax.servlet.RequestDispatcher is tied to. + * Currently this class only supports javax.servlet.Servlet objects + * and java.lang.String objects. If the parameter passed in is not + * a javax.servlet.Servlet object when forward or include is called + * the parameter's toString method is called and sent to System.out. + * Otherwise, the appropriate service method is called. + */ + public RequestDispatcherSimulator( Object dispatchedResource ) + { + this.dispatchedResource = dispatchedResource; + } + /** + * Simulates the forward method of the javax.servlet.RequestDispatcher interface + */ + public void forward( ServletRequest request, ServletResponse response ) throws ServletException, IOException + { + if( dispatchedResource instanceof Servlet ) + ((Servlet)dispatchedResource).service( request, response ); + } + public void include( ServletRequest request, ServletResponse response ) throws ServletException, IOException + { + System.out.println( dispatchedResource.toString() ); + } + + public String getForward() { + if (dispatchedResource instanceof String) + return (String) dispatchedResource; + else + return dispatchedResource.getClass().toString(); + } +} Index: 3rdParty_sources/strutstest/servletunit/ServletConfigSimulator.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/strutstest/servletunit/Attic/ServletConfigSimulator.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/strutstest/servletunit/ServletConfigSimulator.java 17 Aug 2012 15:17:08 -0000 1.1 @@ -0,0 +1,125 @@ +package servletunit; + +// StrutsTestCase - a JUnit extension for testing Struts actions +// within the context of the ActionServlet. +// Copyright (C) 2002 Deryl Seale +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the Apache Software License as +// published by the Apache Software Foundation; either version 1.1 +// of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// Apache Software Foundation Licens for more details. +// +// You may view the full text here: http://www.apache.org/LICENSE.txt + +import javax.servlet.ServletConfig; +import javax.servlet.ServletContext; +import java.util.Enumeration; +import java.util.Hashtable; + +/** + * This class simulates a ServletConfig. + */ + +public class ServletConfigSimulator implements ServletConfig +{ + + private Hashtable parameters; + private ServletContext context; + + public ServletConfigSimulator() + { + parameters=new Hashtable(); + context = new ServletContextSimulator(); + } + + /** + * Returns a String containing the value of the + * named initialization parameter, or null if + * the parameter does not exist. + * + * @param name a String specifying the name + * of the initialization parameter + * + * @return a String containing the value + * of the initialization parameter + * + */ + public String getInitParameter(String name) + { + return (String) parameters.get(name); + } + + /** + * Returns the names of the servlet's initialization parameters + * as an Enumeration of String objects, + * or an empty Enumeration if the servlet has + * no initialization parameters. + * + * @return an Enumeration of String + * objects containing the names of the servlet's + * initialization parameters + * + * + * + */ + public Enumeration getInitParameterNames() + { + return parameters.keys(); + } + + /** + * Returns a reference to the {@link ServletContext} in which the caller + * is executing. + * + * + * @return a {@link ServletContext} object, used + * by the caller to interact with its servlet + * container + * + * @see ServletContext + * + */ + public ServletContext getServletContext() + { + return context; + } + + /** + * Returns the name of this servlet instance. + * The name may be provided via server administration, assigned in the + * web application deployment descriptor, or for an unregistered (and thus + * unnamed) servlet instance it will be the servlet's class name. + * + * @return the String "ActionServlet" + * + * + * + */ + public String getServletName() + { + return "ActionServlet"; + } + + /** + * Sets a named initialization parameter with the supplied + * String value. + * + * @param key a String specifying the name + * of the initialization parameter + * + * @param value a String value for this initialization + * parameter + * + */ + public void setInitParameter(String key,String value) + { + parameters.put(key,value); + } + +} + Index: 3rdParty_sources/strutstest/servletunit/ServletContextSimulator.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/strutstest/servletunit/Attic/ServletContextSimulator.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/strutstest/servletunit/ServletContextSimulator.java 17 Aug 2012 15:17:08 -0000 1.1 @@ -0,0 +1,550 @@ +package servletunit; + +// StrutsTestCase - a JUnit extension for testing Struts actions +// within the context of the ActionServlet. +// Copyright (C) 2002 Deryl Seale +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the Apache Software License as +// published by the Apache Software Foundation; either version 1.1 +// of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// Apache Software Foundation Licens for more details. +// +// You may view the full text here: http://www.apache.org/LICENSE.txt + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import javax.servlet.RequestDispatcher; +import javax.servlet.Servlet; +import javax.servlet.ServletContext; +import javax.servlet.ServletException; +import java.io.InputStream; +import java.io.File; +import java.io.FileInputStream; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.Set; + +/** + * This class simulates a ServletContext. + */ +public class ServletContextSimulator implements ServletContext +{ + + private Hashtable initParameters; + private Hashtable attributes; + private RequestDispatcherSimulator dispatcher = null; + private static Log logger = LogFactory.getLog( ServletContextSimulator.class ); + private File contextDirectory; + + public ServletContextSimulator() { + this.initParameters = new Hashtable(); + this.attributes = new Hashtable(); + } + + /** + * Returns the servlet container attribute with the given name, + * or null if there is no attribute by that name. + * An attribute allows a servlet container to give the + * servlet additional information not + * already provided by this interface. See your + * server documentation for information about its attributes. + * A list of supported attributes can be retrieved using + * getAttributeNames. + * + *

The attribute is returned as a java.lang.Object + * or some subclass. + * Attribute names should follow the same convention as package + * names. The Java Servlet API specification reserves names + * matching java.*, javax.*, + * and sun.*. + * + * + * @param name a String specifying the name + * of the attribute + * + * @return an Object containing the value + * of the attribute, or null + * if no attribute exists matching the given + * name + * + * @see ServletContext#getAttributeNames + * + */ + public Object getAttribute(String name) + { + return attributes.get(name); + } + + /** + * Returns an Enumeration containing the + * attribute names available + * within this servlet context. Use the + * {@link #getAttribute} method with an attribute name + * to get the value of an attribute. + * + * @return an Enumeration of attribute + * names + * + * @see #getAttribute + * + */ + public Enumeration getAttributeNames() + { + return attributes.keys(); + } + + /** + * Unsupported in this version. + */ + public ServletContext getContext(String uripath) + { + throw new UnsupportedOperationException("getContext operation is not supported!"); + } + + /** + * Returns a String containing the value of the named + * context-wide initialization parameter, or null if the + * parameter does not exist. + * + *

This method can make available configuration information useful + * to an entire "web application". For example, it can provide a + * webmaster's email address or the name of a system that holds + * critical data. + * + * @param s a String containing the name of the + * parameter whose value is requested + * + * @return a String containing at least the + * servlet container name and version number + * + * @see javax.servlet.ServletConfig#getInitParameter + */ + public String getInitParameter(String s) + { + return (String) initParameters.get(s); + } + + /** + * Returns the names of the context's initialization parameters as an + * Enumeration of String objects, or an + * empty Enumeration if the context has no initialization + * parameters. + * + * @return an Enumeration of String + * objects containing the names of the context's + * initialization parameters + * + * @see javax.servlet.ServletConfig#getInitParameter + */ + public Enumeration getInitParameterNames() + { + return initParameters.keys(); + } + + /** + * Sets a named initialization parameter with the supplied + * String value. + * + * @param key a String specifying the name + * of the initialization parameter + * + * @param value a String value for this initialization + * parameter + * + */ + public void setInitParameter(String key,String value) + { + initParameters.put(key,value); + } + + /** + * Returns the major version of the Java Servlet API that this + * Web server supports. All implementations that comply + * with Version 2.3 must have this method + * return the integer 2. + * + * @return 2 + * + */ + public int getMajorVersion() + { + return 2; + } + + /** + * Unsupported in this version. + */ + public String getMimeType(String file) + { + throw new UnsupportedOperationException("getMimeType operation is not supported!"); + } + + /** + * Returns the minor version of the Servlet API that this + * Web server supports. All implementations that comply + * with Version 2.3 must have this method + * return the integer 1. + * + * @return 3 + * + */ + public int getMinorVersion() + { + return 3; + } + + public RequestDispatcher getNamedDispatcher(String s) + { + throw new UnsupportedOperationException("getNamedDispatcher operation is not supported!"); + } + + public String getRealPath(String path) + { + if ((contextDirectory == null) || (path == null)) + return null; + else + return (new File(contextDirectory, path)).getAbsolutePath(); + } + + /** + * + * Returns a {@link RequestDispatcher} object that acts + * as a wrapper for the resource located at the given path. + * A RequestDispatcher object can be used to forward + * a request to the resource or to include the resource in a response. + * The resource can be dynamic or static. + * + *

The pathname must begin with a "/" and is interpreted as relative + * to the current context root. Use getContext to obtain + * a RequestDispatcher for resources in foreign contexts. + * This method returns null if the ServletContext + * cannot return a RequestDispatcher. + * + * @param urlpath a String specifying the pathname + * to the resource + * + * @return a RequestDispatcher object + * that acts as a wrapper for the resource + * at the specified path + * + * @see RequestDispatcher + * @see ServletContext#getContext + * + */ + public RequestDispatcher getRequestDispatcher(String urlpath) + { + dispatcher = new RequestDispatcherSimulator(urlpath); + return dispatcher; + } + + /** + * Returns the mock RequestDispatcher object used in this test. + * The RequestDispatcherSimulator contains forwarding information + * that can be used in test validation. + */ + public RequestDispatcherSimulator getRequestDispatcherSimulator() { + return dispatcher; + } + + /** + * TODO: add appropriate comments + */ + public URL getResource(String path) throws MalformedURLException + { + try { + File file = getResourceAsFile(path); + + if (file.exists()) { + return file.toURL(); + } + else { + if(!path.startsWith("/")){ + path = "/" + path; + } + return this.getClass().getResource(path); + } + } catch (Exception e) { + return null; + } + } + + /** + * Returns the resource located at the named path as + * an InputStream object. + * + *

The data in the InputStream can be + * of any type or length. The path must be specified according + * to the rules given in getResource. + * This method returns null if no resource exists at + * the specified path. + * + *

Meta-information such as content length and content type + * that is available via getResource + * method is lost when using this method. + * + *

The servlet container must implement the URL handlers + * and URLConnection objects necessary to access + * the resource. + * + *

In this mock implementation, this method first looks for + * the supplied pathname in the underlying filesystem; if it + * does not exist there, the default Java classloader is used. + * + * + * @param path a String specifying the path + * to the resource + * + * @return the InputStream returned to the + * servlet, or null if no resource + * exists at the specified path + * + * + */ + public InputStream getResourceAsStream(String path) + { + try { + File file = getResourceAsFile(path); + + if (file.exists()) { + return new FileInputStream(file); + } + else { + if(!path.startsWith("/")){ + path = "/" + path; + } + return this.getClass().getResourceAsStream(path); + } + } catch (Exception e) { + System.out.println("caught error: " + e); + e.printStackTrace(); + return null; + } + } + + /** + * Attempts to load a resource from the underlying file system + * and return a file handle to it. + * It first treats the path as an absolute path. If no file is found, + * it attempts to treat the path as relative to the context directory. + * If no file is found, it attempts to treat the path as relative to + * the current directory. + * If all these options fail, the returned file will return false() + * to calls to File.exists(). + * @param path the relative or context-relative path to the file + * @return the refernce to the file (which may or may not exist) + */ + public File getResourceAsFile(String path){ + File file = new File(path); + + // If the path is relative then apply the contextDirectory path if it exists. + if (!file.exists()) + { + if(!path.startsWith("/")){ + path = "/" + path; + } + if((getContextDirectory() != null)) + { + file = new File(getContextDirectory().getAbsolutePath() + path); + }else{ + //try using current directory + file = new File(new File(".").getAbsolutePath() + path); + } + } + return file; + + } + + /** + * Unsupported in this version. + */ + public Set getResourcePaths() + { + throw new UnsupportedOperationException("getResourcePaths operation is not supported!"); + } + + /** + * Returns the name and version of the servlet container on which + * the servlet is running. + * + *

The form of the returned string is + * servername/versionnumber. + * For example, the JavaServer Web Development Kit may return the string + * JavaServer Web Dev Kit/1.0. + * + *

The servlet container may return other optional information + * after the primary string in parentheses, for example, + * JavaServer Web Dev Kit/1.0 (JDK 1.1.6; Windows NT 4.0 x86). + * + * + * @return a String containing at least the + * servlet container name and version number + * + */ + public String getServerInfo() + { + return "MockServletEngine/1.9.5"; + } + + /** + * Unsupported in this version. + */ + public Servlet getServlet(String name) throws ServletException + { + throw new UnsupportedOperationException("getServlet operation is not supported!"); + } + + /** + * Unsupported in this version. + */ + public String getServletContextName() + { + throw new UnsupportedOperationException("getServletContextName operation is not supported!"); + } + + /** + * Unsupported in this version. + */ + public Enumeration getServletNames() + { + throw new UnsupportedOperationException("getServletNames operation is not supported!"); + } + + /** + * Unsupported in this version. + */ + public Enumeration getServlets() + { + throw new UnsupportedOperationException("getServlets operation is not supported!"); + } + + /** + * @deprecated As of Java Servlet API 2.1, use + * @link ServletContext.log(String message, Throwable throwable) + * instead. + * + *

This method was originally defined to write an + * exception's stack trace and an explanatory error message + * to the servlet log file. + * + */ + public void log(Exception exception, String msg) + { + logger.info(msg + "\n" + exception.getClass() + " - " + exception.getMessage()); + } + + /** + * + * Writes the specified message to a servlet log file, which is usually + * an event log. The message provides explanatory information about + * an exception or error or an action the servlet engine takes. The name + * and type of the servlet log file is specific to the servlet engine. + * + * + * @param msg a String specifying the explanatory + * message to be written to the log file + * + */ + public void log(String msg) + { + logger.info(msg); + } + + /** + * Writes the stack trace and an explanatory message + * for a given Throwable exception + * to the servlet log file. The name and type of the servlet log + * file is specific to the servlet engine, but it is usually an event log. + * + * + * @param message a String that + * describes the error or exception + * + * @param throwable the Throwable error + * or exception + * + */ + public void log(String message, Throwable throwable) + { + logger.info(message + "\n" + throwable.getClass() + " - " + throwable.getMessage()); + } + + /** + * Removes the attribute with the given name from + * the servlet context. After removal, subsequent calls to + * {@link #getAttribute} to retrieve the attribute's value + * will return null. + + *

If listeners are configured on the ServletContext the + * container notifies them accordingly. + + * + * + * @param name a String specifying the name + * of the attribute to be removed + * + */ + public void removeAttribute(String name) + { + attributes.remove(name); + } + + /** + * + * Binds an object to a given attribute name in this servlet context. If + * the name specified is already used for an attribute, this + * method will replace the attribute with the new to the new attribute. + *

If listeners are configured on the ServletContext the + * container notifies them accordingly. + *

+ * If a null value is passed, the effect is the same as calling + * removeAttribute(). + * + *

Attribute names should follow the same convention as package + * names. The Java Servlet API specification reserves names + * matching java.*, javax.*, and + * sun.*. + * + * + * @param name a String specifying the name + * of the attribute + * + * @param object an Object representing the + * attribute to be bound + * + * + * + */ + public void setAttribute(String name, Object object) + { + attributes.put(name,object); + } + + /** + * Unsupported in this version. + */ + public Set getResourcePaths(String path) { + throw new UnsupportedOperationException("getResourcePaths operation is not supported!"); + } + + /** + * Sets the absolute context directory to be used in the getRealPath() method. + * @param contextDirectory the absolute path of the root context directory for this application. + */ + public void setContextDirectory(File contextDirectory) { + this.contextDirectory = contextDirectory; + } + + public File getContextDirectory() { + return contextDirectory; + } + + +} Index: 3rdParty_sources/strutstest/servletunit/ServletOutputStreamSimulator.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/strutstest/servletunit/Attic/ServletOutputStreamSimulator.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/strutstest/servletunit/ServletOutputStreamSimulator.java 17 Aug 2012 15:17:08 -0000 1.1 @@ -0,0 +1,56 @@ +package servletunit; + +// StrutsTestCase - a JUnit extension for testing Struts actions +// within the context of the ActionServlet. +// Copyright (C) 2002 Deryl Seale +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the Apache Software License as +// published by the Apache Software Foundation; either version 1.1 +// of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// Apache Software Foundation Licens for more details. +// +// You may view the full text here: http://www.apache.org/LICENSE.txt + +import javax.servlet.ServletOutputStream; +import java.io.IOException; +import java.io.OutputStream; + +public class ServletOutputStreamSimulator extends ServletOutputStream +{ + private OutputStream outStream; + + /** + * Default constructor that sends all output to System.out. + */ + public ServletOutputStreamSimulator() + { + this.outStream = System.out; + } + + /** + * Constructor that sends all output to given OutputStream. + * @param out OutputStream to which all output will be sent. + */ + public ServletOutputStreamSimulator( OutputStream out ) + { + this.outStream = out; + } + + public void write( int b ) + { + try + { + outStream.write( b ); + } + catch( IOException io ) + { + System.err.println("IOException: " + io.getMessage()); + io.printStackTrace(); + } + } +} Index: 3rdParty_sources/strutstest/servletunit/struts/CactusStrutsTestCase.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/strutstest/servletunit/struts/Attic/CactusStrutsTestCase.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/strutstest/servletunit/struts/CactusStrutsTestCase.java 17 Aug 2012 15:17:09 -0000 1.1 @@ -0,0 +1,830 @@ +// StrutsTestCase - a JUnit extension for testing Struts actions +// within the context of the ActionServlet. +// Copyright (C) 2002 Deryl Seale +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the Apache Software License as +// published by the Apache Software Foundation; either version 1.1 +// of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// Apache Software Foundation Licens for more details. +// +// You may view the full text here: http://www.apache.org/LICENSE.txt + +package servletunit.struts; + +import junit.framework.AssertionFailedError; +import org.apache.cactus.ServletTestCase; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.struts.Globals; +import org.apache.struts.action.ActionForm; +import org.apache.struts.action.ActionServlet; + +import javax.servlet.ServletContext; +import javax.servlet.ServletException; +import javax.servlet.ServletConfig; +import javax.servlet.http.*; +import java.util.Enumeration; +import java.util.List; +import java.util.ArrayList; +import java.util.Iterator; + +/** + * CactusStrutsTestCase is an extension of the Cactus ServletTestCase + * base class that provides additional methods to aid in testing + * Struts Action objects. It uses an in-container approach to run + * the servlet container, and tests the execution of Action objects as they + * are actually run through the Struts ActionServlet. CactusStrutsTestCase + * provides methods that set up the request path, request parameters + * for ActionForm subclasses, as well as methods that can verify + * that the correct ActionForward was used and that the proper + * ActionError messages were supplied. + *
+ *
+ * Please note that this class is meant to run in the Cactus + * framework, and you must configure your test environment + * accordingly. Please see http://jakarta.apache.org/cactus + * for more details. + * + */ +public class CactusStrutsTestCase extends ServletTestCase { + + protected ActionServlet actionServlet; + protected HttpServletRequestWrapper requestWrapper; + protected HttpServletResponseWrapper responseWrapper; + protected boolean isInitialized = false; + protected boolean actionServletIsInitialized = false; + protected boolean requestPathIsSet = false; + protected String moduleName; + protected String servletMapping = "*.do"; + + protected static Log logger = LogFactory.getLog(CactusStrutsTestCase.class); + + /** + * Default constructor. + */ + public CactusStrutsTestCase() { + super(); + } + + /** + * Constructor that takes test name parameter, for backwards compatibility with older versions on JUnit. + */ + public CactusStrutsTestCase(String testName) { + super(testName); + } + + /** + * A check that every method should run to ensure that the + * base class setUp method has been called. + */ + private void init() { + if (!isInitialized) { + throw new AssertionFailedError("You are overriding the setUp() method without calling super.setUp(). You must call the superclass setUp() and tearDown() methods in your TestCase subclass to ensure proper initialization."); + } + } + + /** + * Sets up the test fixture for this test. This method creates + * an instance of the ActionServlet, initializes it to validate + * forms and turn off debugging, and clears all other parameters. + */ + protected void setUp() throws Exception { + if (logger.isDebugEnabled()) + logger.debug("Entering"); + try { + + if (actionServlet == null) + actionServlet = new ActionServlet(); + requestWrapper = null; + responseWrapper = null; + ServletContext servletContext = new StrutsServletContextWrapper(this.config.getServletContext()); + this.config = new StrutsServletConfigWrapper(this.config); + ((StrutsServletConfigWrapper) this.config).setServletContext(servletContext); + this.request = new StrutsRequestWrapper(this.request); + this.response = new StrutsResponseWrapper(this.response); + isInitialized = true; + if (logger.isDebugEnabled()) + logger.debug("Exiting"); + } catch (Exception e) { + if (logger.isDebugEnabled()) + logger.debug(e); + throw new AssertionFailedError("Error trying to set up test fixture: " + e.getClass() + " - " + e.getMessage()); + } + } + + /** + * Sets the servlet mapping used to map requests to the Struts controller. This is used to restore + * proper setting after the test has been executed. By default, the stanard "*.do" mapping will be + * restored, so only use this method for non-standard servlet mappings. + * @param servletMapping + */ + public void setServletMapping(String servletMapping) { + this.servletMapping = servletMapping; + } + + protected void tearDown () throws Exception { + if (logger.isTraceEnabled()) + logger.trace("Entering"); + + // remove all RequestProcessor instances from context + // so that web application will function normally. + ServletContext context = this.config.getServletContext(); + List nameList = new ArrayList(); + Enumeration attributeNames = context.getAttributeNames(); + while (attributeNames.hasMoreElements()) { + String name = (String) attributeNames.nextElement(); + if (name.startsWith(Globals.REQUEST_PROCESSOR_KEY)) + nameList.add(name); + } + + // restore the original servlet mapping + ServletConfig originalConfig = ((org.apache.cactus.server.ServletConfigWrapper) this.config).getOriginalConfig(); + ServletContext originalContext = originalConfig.getServletContext(); + originalContext.setAttribute(Globals.SERVLET_KEY,servletMapping); + ((StrutsServletConfigWrapper) config).setServletContext(originalContext); + + + for (Iterator iterator = nameList.iterator(); iterator.hasNext();) { + context.removeAttribute((String) iterator.next()); + } + + if (logger.isTraceEnabled()) + logger.trace("Exiting"); + } + + /** + * Returns an HttpServletRequest object that can be used in + * this test. + */ + public HttpServletRequest getRequest() { + if (logger.isDebugEnabled()) + logger.debug("Entering"); + init(); + if (logger.isDebugEnabled()) + logger.debug("Exiting"); + return this.request; + } + + /** + * Returns a HttpServletRequestWrapper object that can be used + * in this test. Note that if {@link #setRequestWrapper} has not been + * called, this method will return an instance of + * javax.servlet.http.HttpServletRequestWrapper. + */ + public HttpServletRequestWrapper getRequestWrapper() { + if (logger.isDebugEnabled()) + logger.debug("Entering"); + init(); + if (requestWrapper == null) { + if (logger.isDebugEnabled()) + logger.debug("Exiting"); + return new HttpServletRequestWrapper(this.request); + } else { + if (logger.isDebugEnabled()) { + logger.debug("wrapper class is '" + requestWrapper.getClass() + "'"); + } + if (logger.isDebugEnabled()) + logger.debug("Exiting"); + return requestWrapper; + } + } + + /** + * Set this TestCase to use a given HttpServletRequestWrapper + * class when calling Action.execute(). Note that if this + * method is not called, then the normal HttpServletRequest + * object is used. + * + * @param wrapper an HttpServletRequestWrapper object to be + * used when calling Action.execute(). + */ + public void setRequestWrapper(HttpServletRequestWrapper wrapper) { + if (logger.isDebugEnabled()) + logger.debug("Entering - wrapper = " + wrapper); + init(); + if (wrapper == null) { + throw new IllegalArgumentException("wrapper class cannot be null!"); + } else { + if (wrapper.getRequest() == null) + wrapper.setRequest(this.request); + this.requestWrapper = wrapper; + } + if (logger.isDebugEnabled()) + logger.debug("Exiting"); + } + + /** + * Returns an HttpServletResponse object that can be used in + * this test. + */ + public HttpServletResponse getResponse() { + if (logger.isDebugEnabled()) + logger.debug("Entering"); + init(); + if (logger.isDebugEnabled()) + logger.debug("Exiting"); + return this.response; + } + + /** + * Returns an HttpServletResponseWrapper object that can be used in + * this test. Note that if {@link #setResponseWrapper} has not been + * called, this method will return an instance of + * javax.servlet.http.HttpServletResponseWrapper. + */ + public HttpServletResponseWrapper getResponseWrapper() { + if (logger.isDebugEnabled()) + logger.debug("Entering"); + init(); + if (responseWrapper == null) { + if (logger.isDebugEnabled()) + logger.debug("Exiting getResponseWrapper()"); + return new HttpServletResponseWrapper(this.response); + } else { + if (logger.isDebugEnabled()) { + logger.debug("wrapper class is '" + responseWrapper.getClass() + "'"); + } + if (logger.isDebugEnabled()) + logger.debug("getResponseWrapper()"); + return responseWrapper; + } + } + + /** + * Set this TestCase to use a given HttpServletResponseWrapper + * class when calling Action.execute(). Note that if this + * method is not called, then the normal HttpServletResponse + * object is used. + * + * @param wrapper an HttpServletResponseWrapper object to be + * used when calling Action.execute(). + */ + public void setResponseWrapper(HttpServletResponseWrapper wrapper) { + if (logger.isDebugEnabled()) + logger.debug("Entering - wrapper = " + wrapper.getClass()); + init(); + if (wrapper == null) + throw new IllegalArgumentException("wrapper class cannot be null!"); + else { + if (wrapper.getResponse() == null) + wrapper.setResponse(this.response); + if (logger.isDebugEnabled()) + logger.debug("Exiting"); + this.responseWrapper = wrapper; + } + } + + /** + * Returns an HttpSession object that can be used in this + * test. + */ + public HttpSession getSession() { + if (logger.isDebugEnabled()) + logger.debug("Entering"); + init(); + if (logger.isDebugEnabled()) + logger.debug("Exiting"); + return this.session; + } + + /** + * Adds an HttpServletRequest parameter to be used in setting up the + * ActionForm instance to be used in this test. Each parameter added + * should correspond to an attribute in the ActionForm instance used + * by the Action instance being tested. + */ + public void addRequestParameter(String parameterName, String parameterValue) + { + if (logger.isDebugEnabled()) + logger.debug("Entering - paramaterName = " + parameterName + ", parameterValue = " + parameterValue); + init(); + ((StrutsRequestWrapper) this.request).addParameter(parameterName,parameterValue); + if (logger.isDebugEnabled()) + logger.debug("Exiting"); + } + + /** + * Adds an HttpServletRequest parameter that is an array of String values + * to be used in setting up the ActionForm instance to be used in this test. + * Each parameter added should correspond to an attribute in the ActionForm + * instance used by the Action instance being tested. + */ + public void addRequestParameter(String parameterName, String[] parameterValues) + { + if (logger.isDebugEnabled()) + logger.debug("Entering - paramaterName = " + parameterName + ", parameterValue = " + parameterValues); + init(); + ((StrutsRequestWrapper) this.request).addParameter(parameterName,parameterValues); + if (logger.isDebugEnabled()) + logger.debug("Exiting"); + } + + /** + * Clears all request parameters previously set. NOTE: This will not clear + * parameters set using Cactus beginXXX methods! + */ + public void clearRequestParameters() { + init(); + ((StrutsRequestWrapper) request).clearRequestParameters(); + } + + /** + * Sets the request path instructing the ActionServlet to used a + * particual ActionMapping. + * + * @param pathInfo the request path to be processed. This should + * correspond to a particular action mapping, as would normally + * appear in an HTML or JSP source file. + */ + public void setRequestPathInfo(String pathInfo) { + if (logger.isDebugEnabled()) + logger.debug("Entering - pathInfo = " + pathInfo); + init(); + this.setRequestPathInfo("",pathInfo); + if (logger.isDebugEnabled()) + logger.debug("Exiting"); + } + + + /** + * Sets the request path instructing the ActionServlet to used a + * particual ActionMapping. Also sets the ServletPath property + * on the request. + * + * @param moduleName the name of the Struts sub-application with + * which this request is associated, or null if it is the default + * application. + * @param pathInfo the request path to be processed. This should + * correspond to a particular action mapping, as would normally + * appear in an HTML or JSP source file. If this request is part + * of a sub-application, the module name should not appear in the + * request path. + */ + public void setRequestPathInfo(String moduleName, String pathInfo) { + if (logger.isDebugEnabled()) + logger.debug("Entering - moduleName = " + moduleName + ", pathInfo = " + pathInfo); + init(); + ((StrutsRequestWrapper) this.request).setPathInfo(Common.stripActionPath(pathInfo)); + if (moduleName != null) { + if (!moduleName.equals("")) { + if (!moduleName.startsWith("/")) + moduleName = "/" + moduleName; + if (!moduleName.endsWith("/")) + moduleName = moduleName + "/"; + } + if (logger.isDebugEnabled()) { + logger.debug("setting request.ServletPath value = " + moduleName); + } + ((StrutsRequestWrapper) this.request).setServletPath(moduleName); + this.requestPathIsSet = true; + } + if (logger.isDebugEnabled()) + logger.debug("Exiting"); + } + + /** + * Sets an initialization parameter on the + * ActionServlet. Allows you to simulate an init parameter + * that would normally have been found in web.xml. + * @param key the name of the initialization parameter + * @param value the value of the intialization parameter + */ + public void setInitParameter(String key, String value){ + if (logger.isDebugEnabled()) + logger.debug("Entering - key = " + key + ", value = " + value); + this.config.setInitParameter(key, value); + this.actionServletIsInitialized = false; + if (logger.isDebugEnabled()) + logger.debug("Exiting"); + } + + /** + * Sets the location of the Struts configuration file for the default module. + * This method can take either an absolute path, or a relative path. If an + * absolute path is supplied, the configuration file will be loaded from the + * underlying filesystem; otherwise, the ServletContext loader will be used. + */ + public void setConfigFile(String pathname) { + if (logger.isDebugEnabled()) + logger.debug("Entering - pathname = " + pathname); + init(); + setConfigFile(null,pathname); + if (logger.isDebugEnabled()) + logger.debug("Exiting"); + } + + /** + * Sets the struts configuration file for a given sub-application. + * This method can take either an absolute path, or a relative path. If an + * absolute path is supplied, the configuration file will be loaded from the + * underlying filesystem; otherwise, the ServletContext loader will be used. + * + * @param moduleName the name of the sub-application, or null if this is the default application + * @param pathname the location of the configuration file for this sub-application + */ + public void setConfigFile(String moduleName, String pathname) { + if (logger.isDebugEnabled()) + logger.debug("Entering - moduleName = " + moduleName + ", pathname = " + pathname); + init(); + if (moduleName == null) + this.config.setInitParameter("config",pathname); + else + this.config.setInitParameter("config/" + moduleName,pathname); + actionServletIsInitialized = false; + if (logger.isDebugEnabled()) + logger.debug("Exiting"); + } + + /** + * Returns the ActionServlet controller used in this + * test. + * + */ + public ActionServlet getActionServlet() { + if (logger.isDebugEnabled()) + logger.debug("Entering"); + init(); + try { + if (!actionServletIsInitialized) { + // the RequestProcessor holds on to the ServletContext, so + // we need to ensure that it is replaced for each test. + ServletContext context = config.getServletContext(); + String name = "org.apache.struts.action.REQUEST_PROCESSOR"; + + // remove request processor for default module + Object obj = context.getAttribute(name); + if (obj != null) { + config.getServletContext().removeAttribute(name); + } + + // remove request processor for sub-applications, if used. + // todo: this seems pretty redundant.. may want to make this cleaner. + String moduleName = request.getServletPath() != null ? request.getServletPath() : ""; + + if (moduleName.endsWith("/")) + moduleName = moduleName.substring(0,moduleName.lastIndexOf("/")); + + obj = context.getAttribute(name + moduleName); + if (obj != null) { + config.getServletContext().removeAttribute(name + moduleName); + } + + this.actionServlet.init(config); + actionServletIsInitialized = true; + } + if (logger.isDebugEnabled()) + logger.debug("Exiting"); + return this.actionServlet; + } catch (ServletException e) { + if (logger.isDebugEnabled()) + logger.debug("Error in getActionServlet()",e.getRootCause()); + throw new AssertionFailedError("Error while initializing ActionServlet: " + e.getMessage()); + } + } + + /** + * Sets the ActionServlet to be used in this test execution. This + * method should only be used if you plan to use a customized + * version different from that provided in the Struts distribution. + */ + public void setActionServlet(ActionServlet servlet) { + if (logger.isDebugEnabled()) + logger.debug("Entering - servlet = " + servlet); + init(); + if (servlet == null) + throw new AssertionFailedError("Cannot set ActionServlet to null"); + this.actionServlet = servlet; + actionServletIsInitialized = false; + if (logger.isDebugEnabled()) + logger.debug("Exiting"); + } + + /** + * Executes the Action instance to be tested. This method initializes + * the ActionServlet, sets up and optionally validates the ActionForm + * bean associated with the Action to be tested, and then calls the + * Action.execute() method. Results are stored for further validation. + * + * @exception AssertionFailedError if there are any execution + * errors while calling Action.execute() or ActionForm.validate(). + * + */ + public void actionPerform() { + if (logger.isDebugEnabled()) + logger.debug("Entering"); + if(!this.requestPathIsSet){ + throw new IllegalStateException("You must call setRequestPathInfo() prior to calling actionPerform()."); + } + init(); + try { + HttpServletRequest request = this.request; + HttpServletResponse response = this.response; + // make sure errors are cleared from last test. + request.removeAttribute(Globals.ERROR_KEY); + request.removeAttribute(Globals.MESSAGE_KEY); + + if (this.requestWrapper != null) + request = this.requestWrapper; + if (this.responseWrapper != null) + response = this.responseWrapper; + + ActionServlet actionServlet = this.getActionServlet(); + actionServlet.doPost(request,response); + if (logger.isDebugEnabled()) + logger.debug("Exiting"); + } catch (NullPointerException npe) { + String message = "A NullPointerException was thrown. This may indicate an error in your ActionForm, or " + + "it may indicate that the Struts ActionServlet was unable to find struts config file. " + + "TestCase is running from " + System.getProperty("user.dir") + " directory."; + throw new ExceptionDuringTestError(message, npe); + } catch(Exception e){ + throw new ExceptionDuringTestError("An uncaught exception was thrown during actionExecute()", e); + } + } + + /** + * Returns the forward sent to RequestDispatcher. + */ + protected String getActualForward() { + if (logger.isDebugEnabled()) + logger.debug("Entering"); + if (response.containsHeader("Location")) { + return Common.stripJSessionID(((StrutsResponseWrapper) response).getRedirectLocation()); + } else { + String forward = ((StrutsServletContextWrapper) this.actionServlet.getServletContext()).getForward(); + if (logger.isDebugEnabled()) { + logger.debug("actual forward = " + forward); + } + if (forward == null) { + if (logger.isDebugEnabled()) + logger.debug("Exiting"); + return null; + } else { + String temp = Common.stripJSessionID(forward); + if (!temp.startsWith("/")) + temp = "/" + temp; + String strippedForward = request.getContextPath() + temp; + if (logger.isDebugEnabled()) { + logger.debug("stripped forward and added context path = " + strippedForward); + } + if (logger.isDebugEnabled()) + logger.debug("Exiting"); + return strippedForward; + } + } + + } + + /** + * Verifies if the ActionServlet controller used this forward. + * + * @param forwardName the logical name of a forward, as defined + * in the Struts configuration file. This can either refer to a + * global forward, or one local to the ActionMapping. + * + * @exception AssertionFailedError if the ActionServlet controller + * used a different forward than forwardName after + * executing an Action object. + */ + public void verifyForward(String forwardName) throws AssertionFailedError { + if (logger.isDebugEnabled()) + logger.debug("Entering - forwardName = " + forwardName); + init(); + Common.verifyForwardPath(request.getPathInfo(),forwardName,getActualForward(),false,request,config.getServletContext(),config); + if (logger.isDebugEnabled()) + logger.debug("Exiting"); + } + + /** + * Verifies if the ActionServlet controller used this actual path + * as a forward. + * + * @param forwardPath an absolute pathname to which the request + * is to be forwarded. + * + * @exception AssertionFailedError if the ActionServlet controller + * used a different forward path than forwardPath after + * executing an Action object. + */ + public void verifyForwardPath(String forwardPath) throws AssertionFailedError { + if (logger.isDebugEnabled()) + logger.debug("Entering - forwardPath = " + forwardPath); + init(); + String actualForward = getActualForward(); + + if ((actualForward == null) && (forwardPath == null)) { +// actions can return null forwards. + return; + } + + forwardPath = request.getContextPath() + forwardPath; + + if (actualForward == null) { + if (logger.isDebugEnabled()) { + logger.debug("actualForward is null - this usually means it is not mapped properly."); + } + throw new AssertionFailedError("Was expecting '" + forwardPath + "' but it appears the Action has tried to return an ActionForward that is not mapped correctly."); + } + if (logger.isDebugEnabled()) { + logger.debug("expected forward = '" + forwardPath + "' - actual forward = '" + actualForward + "'"); + } + if (!(actualForward.equals(forwardPath))) + throw new AssertionFailedError("was expecting '" + forwardPath + "' but received '" + actualForward + "'"); + if (logger.isDebugEnabled()) + logger.debug("Exiting"); + } + + /** + * Verifies if the ActionServlet controller forwarded to the defined + * input path. + * + * @exception AssertionFailedError if the ActionServlet controller + * used a different forward than the defined input path after + * executing an Action object. + */ + public void verifyInputForward() { + if (logger.isDebugEnabled()) + logger.debug("Entering"); + init(); + Common.verifyForwardPath(request.getPathInfo(),null,getActualForward(),true,request,config.getServletContext(),config); + if (logger.isDebugEnabled()) + logger.debug("Exiting"); + } + + /** + * Verifies that the ActionServlet controller used this forward and Tiles definition. + * + * @param forwardName the logical name of a forward, as defined + * in the Struts configuration file. This can either refer to a + * global forward, or one local to the ActionMapping. + * + * @param definitionName the name of a Tiles definition, as defined + * in the Tiles configuration file. + * + * @exception AssertionFailedError if the ActionServlet controller + * used a different forward or tiles definition than those given after + * executing an Action object. + */ + public void verifyTilesForward(String forwardName, String definitionName) { + if (logger.isTraceEnabled()) + logger.trace("Entering - forwardName=" + forwardName + ", definitionName=" + definitionName); + init(); + Common.verifyTilesForward(request.getPathInfo(),forwardName,definitionName,false,request,config.getServletContext(),config); + if (logger.isTraceEnabled()) + logger.trace("Exiting"); + } + + /** + * Verifies that the ActionServlet controller forwarded to the defined + * input Tiles definition. + * + * @param definitionName the name of a Tiles definition, as defined + * in the Tiles configuration file. + * + * @exception AssertionFailedError if the ActionServlet controller + * used a different forward than the defined input path after + * executing an Action object. + */ + public void verifyInputTilesForward(String definitionName) { + if (logger.isTraceEnabled()) + logger.trace("Entering - defintionName=" + definitionName); + init(); + Common.verifyTilesForward(request.getPathInfo(),null,definitionName,true,request,config.getServletContext(),config); + if (logger.isTraceEnabled()) + logger.trace("Exiting"); + } + + /** + * Verifies if the ActionServlet controller sent these error messages. + * There must be an exact match between the provided error messages, and + * those sent by the controller, in both name and number. + * + * @param errorNames a String array containing the error message keys + * to be verified, as defined in the application resource properties + * file. + * + * @exception AssertionFailedError if the ActionServlet controller + * sent different error messages than those in errorNames + * after executing an Action object. + */ + + public void verifyActionErrors(String[] errorNames) { + if (logger.isDebugEnabled()) + logger.debug("Entering - errorNames = " + errorNames); + init(); + Common.verifyActionMessages(request,errorNames,Globals.ERROR_KEY,"error"); + if (logger.isDebugEnabled()) + logger.debug("Exiting"); + } + + /** + * Verifies that the ActionServlet controller sent no error messages upon + * executing an Action object. + * + * @exception AssertionFailedError if the ActionServlet controller + * sent any error messages after excecuting and Action object. + */ + public void verifyNoActionErrors() { + if (logger.isDebugEnabled()) + logger.debug("Entering"); + init(); + Common.verifyNoActionMessages(request,Globals.ERROR_KEY,"error"); + if (logger.isDebugEnabled()) + logger.debug("Exiting"); + } + + /** + * Verifies if the ActionServlet controller sent these action messages. + * There must be an exact match between the provided action messages, and + * those sent by the controller, in both name and number. + * + * @param messageNames a String array containing the action message keys + * to be verified, as defined in the application resource properties + * file. + * + * @exception AssertionFailedError if the ActionServlet controller + * sent different action messages than those in messageNames + * after executing an Action object. + */ + public void verifyActionMessages(String[] messageNames) { + if (logger.isDebugEnabled()) + logger.debug("Entering - messageNames = " + messageNames); + init(); + Common.verifyActionMessages(request,messageNames,Globals.MESSAGE_KEY,"action"); + if (logger.isDebugEnabled()) + logger.debug("Exiting"); + } + + /** + * Verifies that the ActionServlet controller sent no action messages upon + * executing an Action object. + * + * @exception AssertionFailedError if the ActionServlet controller + * sent any action messages after excecuting and Action object. + */ + public void verifyNoActionMessages() { + if (logger.isDebugEnabled()) + logger.debug("Entering"); + init(); + Common.verifyNoActionMessages(request,Globals.MESSAGE_KEY,"action"); + if (logger.isDebugEnabled()) + logger.debug("Exiting"); + } + + /** + * Returns the ActionForm instance stored in either the request or session. Note + * that no form will be returned if the Action being tested cleans up the form + * instance. + * + * @ return the ActionForm instance used in this test, or null if it does not exist. + */ + public ActionForm getActionForm() { + if (logger.isDebugEnabled()) + logger.debug("Entering"); + init(); + if (logger.isDebugEnabled()) + logger.debug("Exiting"); + return Common.getActionForm(request.getPathInfo(),request,config.getServletContext()); + } + + /** + * Sets an ActionForm instance to be used in this test. The given ActionForm instance + * will be stored in the scope specified in the Struts configuration file (ie: request + * or session). Note that while this ActionForm instance is passed to the test, Struts + * will still control how it is used. In particular, it will call the ActionForm.reset() + * method, so if you override this method in your ActionForm subclass, you could potentially + * reset attributes in the form passed through this method. + * + * @param form the ActionForm instance to be used in this test. + */ + public void setActionForm(ActionForm form) { + if (logger.isDebugEnabled()) + logger.debug("Entering - form = " + form); + init(); + // make sure ActionServlet is initialized. + Common.setActionForm(form,request,request.getPathInfo(),config.getServletContext()); + if (logger.isDebugEnabled()) + logger.debug("Exiting"); + } + + /** + * Instructs StrutsTestCase to fully process a forward request. By default, StrutsTestCase + * stops processing a request as soon as the forward path has been collected, in order to avoid + * side effects; calling this method overrides this behavior. + * @param flag set to true to fully process forward requests + */ + public void processRequest(boolean flag) { + if (logger.isTraceEnabled()) + logger.trace("Entering - flag=" + flag); + ((StrutsServletContextWrapper) this.config.getServletContext()).setProcessRequest(flag); + if (logger.isTraceEnabled()) + logger.trace("Exiting"); + } + +} + Index: 3rdParty_sources/strutstest/servletunit/struts/Common.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/strutstest/servletunit/struts/Attic/Common.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/strutstest/servletunit/struts/Common.java 17 Aug 2012 15:17:09 -0000 1.1 @@ -0,0 +1,512 @@ +// StrutsTestCase - a JUnit extension for testing Struts actions +// within the context of the ActionServlet. +// Copyright (C) 2002 Deryl Seale +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the Apache Software License as +// published by the Apache Software Foundation; either version 1.1 +// of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// Apache Software Foundation Licens for more details. +// +// You may view the full text here: http://www.apache.org/LICENSE.txt + +package servletunit.struts; + +import junit.framework.AssertionFailedError; +import org.apache.struts.action.*; +import org.apache.struts.tiles.*; +import org.apache.struts.config.ModuleConfig; +import org.apache.struts.config.ForwardConfig; +import org.apache.struts.config.ActionConfig; +import org.apache.struts.Globals; +import org.apache.struts.util.RequestUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.commons.collections.Transformer; +import org.apache.commons.collections.iterators.TransformIterator; +import org.apache.commons.collections.IteratorUtils; + +import javax.servlet.ServletConfig; +import javax.servlet.ServletContext; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpSession; +import java.util.Iterator; +import java.util.Arrays; + + +/** + * Contains code common to both MockStrutsTestCase and CactusStrutsTestCase. + * It's always good to get rid of redundancy! + */ +public class Common { + + protected static final String INCLUDE_SERVLET_PATH = RequestProcessor.INCLUDE_SERVLET_PATH; + protected static Log logger = LogFactory.getLog(Common.class); + + /** + * Common method to verify action errors and action messages. + */ + protected static void verifyNoActionMessages(HttpServletRequest request, String key, String messageLabel) { + if (logger.isTraceEnabled()) + logger.trace("Entering - request = " + request + ", key = " + key + ", messageLabel = " + messageLabel); + ActionMessages messages = (ActionMessages) request.getAttribute(key); + if (logger.isDebugEnabled()) { + logger.debug("retrieved ActionMessages = " + messages); + } + if (messages != null) { + Iterator iterator = messages.get(); + if (iterator.hasNext()) { + StringBuffer messageText = new StringBuffer(); + while (iterator.hasNext()) { + messageText.append(" \""); + messageText.append(((ActionMessage) iterator.next()).getKey()); + messageText.append("\""); + } + throw new AssertionFailedError("was expecting no " + messageLabel + " messages, but received: " + messageText.toString()); + } + } + if (logger.isTraceEnabled()) + logger.trace("Exiting"); + } + + /** + * Common method to verify action errors and action messages. + */ + protected static void verifyActionMessages(HttpServletRequest request, String[] messageNames, String key, String messageLabel) { + if (logger.isTraceEnabled()) + logger.trace("Entering - request = " + request + ", messageNames = " + messageNames + ", key = " + key + ", messageLabel = " + messageLabel); + + ActionMessages messages = (ActionMessages) request.getAttribute(key); + if (logger.isDebugEnabled()) { + logger.debug("retrieved ActionMessages = " + messages); + } + + if (messages == null) { + throw new AssertionFailedError("was expecting some " + messageLabel + " messages, but received none."); + } + /* check length of messages as optimization */ + else if (messages.size() != messageNames.length) { + throw new AssertionFailedError("was expecting " + messageNames.length + " " + messageLabel + " message(s), but received " + messages.size() + " " + messageLabel + " message(s)"); + } + else { + /* alphabetize the two lists of message keys and compare them */ + + Iterator iter = new TransformIterator( messages.get(), + new Transformer(){ + public Object transform( Object input ) + { + return ((ActionMessage) input).getKey(); + } + } ); + + String[] messageKeys = (String[]) IteratorUtils.toArray(iter,String.class ); + + Arrays.sort( messageKeys ); + Arrays.sort( messageNames ); + + for ( int i = 0; i < messageNames.length;i++) { + if ( !messageNames[i].equals(messageKeys[i])) { + StringBuffer mks = new StringBuffer(); + StringBuffer mns = new StringBuffer(); + + for ( int j = 0; j < messageKeys.length; j++) mks.append( messageKeys[j] + " " ); + for ( int k = 0; k < messageNames.length; k++) mns.append( messageNames[k] + " " ); + + throw new AssertionFailedError("received " + messageLabel + " messages: (" + mks + ") but expected (" + mns + ")"); + } + } + } + if (logger.isTraceEnabled()) + logger.trace("verifyActionMessages()"); + } + + + /** + * Retrieves a forward uri for tile - this is required for applications + * using the tiles framework, since the actual forward URI must + * be fetched from the tile definition. + */ + protected static ComponentDefinition getTilesForward(String forwardPath, HttpServletRequest request, ServletContext context, ServletConfig config) { + + if (logger.isTraceEnabled()) + logger.trace("Entering - forwardPath = " + forwardPath + ", request = " + request + ", context = " + context + ", config = " + config); + + String result = null; + try { + ComponentDefinition definition; + ComponentDefinition actionDefinition; + + // Get definition of tiles/component corresponding to uri. + definition = TilesUtil.getDefinition(forwardPath, request, context); + if (definition != null) { + if (logger.isDebugEnabled()) { + logger.debug("found tiles definition - '" + forwardPath + "' = '" + result + "'"); + } + } + + actionDefinition = DefinitionsUtil.getActionDefinition(request); + if (actionDefinition != null) { + if (logger.isDebugEnabled()) { + logger.debug("found tiles definition for action - '" + forwardPath + "' = '" + result + "'"); + } + } + + if (actionDefinition != null) { + if (logger.isDebugEnabled()) + logger.debug("definition attributes: " + actionDefinition.getAttributes()); + return actionDefinition; + } else { + if (logger.isDebugEnabled() && (definition != null)) + logger.debug("definition attributes: " + definition.getAttributes()); + return definition; + } + } catch (NoSuchDefinitionException nsde) { + if (logger.isTraceEnabled()) + logger.trace("Exiting - caught NoSuchDefinitionException"); + return null; + } catch (DefinitionsFactoryException dfe) { + if (logger.isTraceEnabled()) + logger.trace("Exiting - caught DefinitionsFactoryException"); + return null; + } catch (NullPointerException npe) { + // can happen if tiles is not at all used. + if (logger.isDebugEnabled()) { + logger.debug("Exiting - caught NullPointerException"); + } + return null; + } + } + + /** + * Verifies that ActionServlet used this logical forward or input mapping with this tile definition. + * + * @throws AssertionFailedError if the expected and actual tiles definitions do not match. + */ + protected static void verifyTilesForward(String actionPath, String forwardName, String expectedDefinition, boolean isInputPath, HttpServletRequest request, ServletContext context, ServletConfig config) { + if (logger.isTraceEnabled()) + logger.trace("Entering - actionPath = " + actionPath + ", forwardName = " + forwardName + ", expectedDefinition = " + expectedDefinition); + + String definitionName = null; + + if ((forwardName == null) && (isInputPath)) { + if (logger.isDebugEnabled()) { + logger.debug("processing an input forward"); + } + forwardName = getActionConfig(actionPath, request, context).getInput(); + if (logger.isDebugEnabled()) { + logger.debug("retrieved input forward name = " + forwardName); + } + if (forwardName == null) + throw new AssertionFailedError("Trying to validate against an input mapping, but none is defined for this Action."); + ComponentDefinition definition = getTilesForward(forwardName, request, context, config); + if (definition != null) + definitionName = definition.getName(); + } + + if (!isInputPath) { + if (logger.isDebugEnabled()) { + logger.debug("processing normal forward"); + } + ForwardConfig expectedForward = findForward(actionPath, forwardName, request, context); + if (expectedForward == null) + throw new AssertionFailedError("Cannot find forward '" + forwardName + "' - it is possible that it is not mapped correctly."); + forwardName = expectedForward.getPath(); + if (logger.isDebugEnabled()) { + logger.debug("retrieved forward name = " + forwardName); + } + + ComponentDefinition definition = getTilesForward(forwardName, request, context, config); + if (definition != null) + definitionName = definition.getName(); + } + if (definitionName == null) + throw new AssertionFailedError("Could not find tiles definition mapped to forward '" + forwardName + "'"); + if (!definitionName.equals(expectedDefinition)) + throw new AssertionFailedError("Was expecting tiles definition '" + expectedDefinition + "' but received '" + definitionName + "'"); + if (logger.isTraceEnabled()) + logger.trace("Exiting"); + } + + /** + * Verifies that ActionServlet used this logical forward or input mapping. + * + * @throws AssertionFailedError if expected and actual paths do not match. + */ + protected static void verifyForwardPath(String actionPath, String forwardName, String actualForwardPath, boolean isInputPath, HttpServletRequest request, ServletContext context, ServletConfig config) { + + if (logger.isTraceEnabled()) + logger.trace("Entering - actionPath = " + actionPath + ", forwardName = " + forwardName + ", actualForwardPath = " + actualForwardPath); + + boolean usesTiles = false; + boolean useModules = false; + + if ((forwardName == null) && (isInputPath)) { + if (logger.isDebugEnabled()) { + logger.debug("processing an input forward"); + } + forwardName = getActionConfig(actionPath, request, context).getInput(); + if (logger.isDebugEnabled()) { + logger.debug("retrieved input forward name = " + forwardName); + } + if (forwardName == null) + throw new AssertionFailedError("Trying to validate against an input mapping, but none is defined for this Action."); + String tilesForward = null; + ComponentDefinition definition = getTilesForward(forwardName, request, context, config); + if (definition != null) + tilesForward = definition.getPath(); + if (tilesForward != null) { + forwardName = tilesForward; + usesTiles = true; + if (logger.isDebugEnabled()) { + logger.debug("retrieved tiles definition for forward = " + forwardName); + } + } + } + if (!isInputPath) { + if (logger.isDebugEnabled()) { + logger.debug("processing normal forward"); + } + + // check for a null forward, now allowed in Struts 1.1 + if (forwardName == null) { + if (actualForwardPath == null) + return; + else + throw new AssertionFailedError("Expected a null forward from action, but received '" + actualForwardPath + "'"); + } + + ForwardConfig expectedForward = findForward(actionPath, forwardName, request, context); + if (expectedForward == null) + throw new AssertionFailedError("Cannot find forward '" + forwardName + "' - it is possible that it is not mapped correctly."); + forwardName = expectedForward.getPath(); + if (logger.isDebugEnabled()) { + logger.debug("retrieved forward name = " + forwardName); + } + + String tilesForward = null; + ComponentDefinition definition = getTilesForward(forwardName, request, context, config); + if (definition != null) + tilesForward = definition.getPath(); + if (tilesForward != null) { + forwardName = tilesForward; + + usesTiles = true; + if (logger.isDebugEnabled()) { + logger.debug("retrieved tiles definition for forward = " + forwardName); + } + } + // some fowards cross outside modules - check if we need the module + // in the path or not. + useModules = !expectedForward.getContextRelative (); + } + + String moduleName = request.getServletPath() != null ? request.getServletPath() : ""; + if ((moduleName == null || moduleName.equalsIgnoreCase("")) && request.getAttribute(INCLUDE_SERVLET_PATH) != null) + // check to see if this is a MockStrutsTestCase call + moduleName = (String) request.getAttribute(INCLUDE_SERVLET_PATH); + + if ((moduleName != null) && (moduleName.length() > 0)) + moduleName = moduleName.substring(moduleName.indexOf('/'),moduleName.lastIndexOf('/')); + else + moduleName = ""; + + if (!forwardName.startsWith("/")) + forwardName = "/" + forwardName; + + if (usesTiles) + forwardName = request.getContextPath() + forwardName; + else if (useModules || isInputPath) + forwardName = request.getContextPath() + moduleName + forwardName; + else + forwardName = request.getContextPath() + forwardName; + if (logger.isDebugEnabled()) { + logger.debug("added context path and module name to forward = " + forwardName); + } + if (actualForwardPath == null) { + if (logger.isDebugEnabled()) { + logger.debug("actualForwardPath is null - this usually means it is not mapped properly."); + } + throw new AssertionFailedError("Was expecting '" + forwardName + "' but it appears the Action has tried to return an ActionForward that is not mapped correctly."); + } + if (logger.isDebugEnabled()) { + logger.debug("expected forward = '" + forwardName + "' - actual forward = '" + actualForwardPath + "'"); + } + if (!forwardName.equals(stripJSessionID(actualForwardPath))) + throw new AssertionFailedError("was expecting '" + forwardName + "' but received '" + actualForwardPath + "'"); + if (logger.isTraceEnabled()) + logger.trace("Exiting"); + } + + /** + * Strips off *.do from action paths specified as such. + */ + protected static String stripActionPath(String path) { + if (logger.isTraceEnabled()) + logger.trace("Entering - path = " + path); + if (path == null) + return null; + + int slash = path.lastIndexOf("/"); + int period = path.lastIndexOf("."); + if ((period >= 0) && (period > slash)) + path = path.substring(0, period); + if (logger.isTraceEnabled()) + logger.trace("Exiting - returning path = " + path); + return path; + } + + /** + * Strip ;jsessionid= from path. + * @return stripped path + */ + protected static String stripJSessionID(String path) { + if (logger.isTraceEnabled()) + logger.trace("Entering - path = " + path); + if (path == null) + return null; + + String pathCopy = path.toLowerCase(); + int jsess_idx = pathCopy.indexOf(";jsessionid="); + if (jsess_idx > 0) { + StringBuffer buf = new StringBuffer(path); + + int queryIndex = pathCopy.indexOf("?"); + // Strip jsessionid from obtained path, but keep query string + if (queryIndex > 0) + path = buf.delete(jsess_idx, queryIndex).toString(); + // Strip jsessionid from obtained path + else + path = buf.delete(jsess_idx, buf.length()).toString(); + } + if (logger.isTraceEnabled()) + logger.trace("Exiting - returning path = " + path); + return path; + } + + /** + * Returns any ActionForm instance stored in the request or session, if available. + */ + protected static ActionForm getActionForm(String actionPath, HttpServletRequest request, ServletContext context) { + if (logger.isTraceEnabled()) + logger.trace("Entering - actionPath = " + actionPath + ", request = " + request + ", context = " + context); + ActionForm form; + ActionConfig actionConfig = getActionConfig(actionPath, request, context); + if ("request".equals(actionConfig.getScope())) { + if (logger.isDebugEnabled()) { + logger.debug("looking for form in request scope"); + } + form = (ActionForm) request.getAttribute(actionConfig.getAttribute()); + } else { + if (logger.isDebugEnabled()) { + logger.debug("looking for form in session scope"); + } + HttpSession session = request.getSession(); + form = (ActionForm) session.getAttribute(actionConfig.getAttribute()); + } + if (logger.isTraceEnabled()) + logger.trace("Exiting"); + return form; + } + + /** + * Returns a ForwardConfig for the given forward name. This method first searches for the forward in the supplied + * action mapping. If it is not defined there, or if the mapping is not provided, it searches for it globally. + */ + protected static ForwardConfig findForward(String mappingName, String forwardName, HttpServletRequest request, ServletContext context) { + if (logger.isTraceEnabled()) + logger.trace("Entering - mappingName = " + mappingName + ", forwardName = " + forwardName + ", request = " + request + ", context = " + context); + ForwardConfig forward = null; + // first, look for forward in mapping (if it's defined) + if (mappingName != null) { + ActionConfig mapping = getActionConfig(mappingName, request, context); + forward = mapping == null ? null : mapping.findForwardConfig(forwardName); + } + // if it's not there, check for global forwards + if (forward == null) { + if (logger.isDebugEnabled()) + logger.debug("looking for forward globally"); + ModuleConfig moduleConfig = getModuleConfig(request,context); + forward = moduleConfig.findForwardConfig(forwardName); + } + if (logger.isDebugEnabled()) { + logger.debug("retrieved forward = " + forward); + } + if (logger.isTraceEnabled()) + logger.trace("Exiting"); + return forward; + } + + /** + * Returns the configuration for the given action mapping. + */ + protected static ActionConfig getActionConfig(String mappingName, HttpServletRequest request, ServletContext context) { + if (logger.isTraceEnabled()) + logger.trace("Entering - mappingName = " + mappingName + ", request = " + request + ", context = " + context); + ModuleConfig config = getModuleConfig(request, context); + ActionMapping actionMapping = (ActionMapping) config.findActionConfig(mappingName); + if (logger.isDebugEnabled()) { + logger.debug("retrieved mapping = " + actionMapping); + } + if (logger.isTraceEnabled()) + logger.trace("Exiting"); + return actionMapping; + } + + /** + * Returns the configuration for the current module. + */ + protected static ModuleConfig getModuleConfig(HttpServletRequest request, ServletContext context) { + if (logger.isTraceEnabled()) + logger.trace("Entering - request = " + request + ", context = " + context); + if (logger.isDebugEnabled()) { + logger.debug("looking for config in request context"); + } + ModuleConfig config = (ModuleConfig) request.getAttribute(Globals.MODULE_KEY); + if (config == null) { + if (logger.isDebugEnabled()) { + logger.debug("looking for config in application context"); + } + config = (ModuleConfig) context.getAttribute(Globals.MODULE_KEY); + } + if (logger.isTraceEnabled()) + logger.trace("Exiting - returning " + config); + return config; + + } + + /** + * Sets an ActionForm instance in the request. + */ + protected static void setActionForm(ActionForm form, HttpServletRequest request, String actionPath, ServletContext context) { + if (logger.isTraceEnabled()) + logger.trace("Entering - form = " + form + ", request = " + request + ", actionPath = " + actionPath + ", context = " + context); + + if (actionPath == null || actionPath.equalsIgnoreCase("")) + throw new IllegalStateException("You must call setRequestPathInfo() before calling setActionForm()!"); + + ActionConfig actionConfig = getActionConfig(actionPath, request, context); + if (actionConfig == null) { + RequestUtils.selectModule(request,context); + actionConfig = getActionConfig(actionPath, request, context); + } + + if (actionConfig.getScope().equals("request")) { + if (logger.isDebugEnabled()) { + logger.debug("setting form in request context"); + } + request.setAttribute(actionConfig.getAttribute(), form); + } else { + if (logger.isDebugEnabled()) { + logger.debug("setting form in session context"); + } + request.getSession().setAttribute(actionConfig.getAttribute(), form); + } + if (logger.isTraceEnabled()) + logger.trace("Exiting"); + } + +} Index: 3rdParty_sources/strutstest/servletunit/struts/ExceptionDuringTestError.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/strutstest/servletunit/struts/Attic/ExceptionDuringTestError.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/strutstest/servletunit/struts/ExceptionDuringTestError.java 17 Aug 2012 15:17:09 -0000 1.1 @@ -0,0 +1,87 @@ +// StrutsTestCase - a JUnit extension for testing Struts actions +// within the context of the ActionServlet. +// Copyright (C) 2002 Deryl Seale +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the Apache Software License as +// published by the Apache Software Foundation; either version 1.1 +// of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// Apache Software Foundation Licens for more details. +// +// You may view the full text here: http://www.apache.org/LICENSE.txt +package servletunit.struts; + +import java.io.*; +import javax.servlet.ServletException; +/** + *

Title: ExceptionDuringTestError

+ *

Description: An error indicating an uncaught exception + * occurred during testing

+ *

Copyright: Copyright (c) 2003

+ * @author Sean Pritchard + * @version 1.0 + */ +public class ExceptionDuringTestError extends Error { + + Throwable rootCause; + + public ExceptionDuringTestError(String message, Throwable rootCause) { + super(message); + this.rootCause = rootCause; + } + + public void printStackTrace(){ + super.printStackTrace(); + System.out.println("------------"); + System.out.println("Root Cause:"); + System.out.println("------------"); + rootCause.printStackTrace(); + if (rootCause instanceof ServletException){ + Throwable root2 = ((ServletException)rootCause).getRootCause(); + if(root2!=null){ + System.out.println("------------"); + System.out.println("Root Cause:"); + System.out.println("------------"); + root2.printStackTrace(); + } + } + } + + public void printStackTrace(PrintStream stream){ + super.printStackTrace(stream); + stream.println("------------"); + stream.println("Root Cause:"); + stream.println("------------"); + rootCause.printStackTrace(stream); + if (rootCause instanceof ServletException){ + Throwable root2 = ((ServletException)rootCause).getRootCause(); + if(root2!=null){ + stream.println("------------"); + stream.println("Root Cause:"); + stream.println("------------"); + root2.printStackTrace(stream); + } + } + } + + public void printStackTrace(PrintWriter stream){ + super.printStackTrace(stream); + stream.println("------------"); + stream.println("Root Cause:"); + stream.println("------------"); + rootCause.printStackTrace(stream); + if (rootCause instanceof ServletException){ + Throwable root2 = ((ServletException)rootCause).getRootCause(); + if(root2!=null){ + stream.println("------------"); + stream.println("Root Cause:"); + stream.println("------------"); + root2.printStackTrace(stream); + } + } + } +} \ No newline at end of file Index: 3rdParty_sources/strutstest/servletunit/struts/MockStrutsTestCase.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/strutstest/servletunit/struts/Attic/MockStrutsTestCase.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/strutstest/servletunit/struts/MockStrutsTestCase.java 17 Aug 2012 15:17:09 -0000 1.1 @@ -0,0 +1,897 @@ +// StrutsTestCase - a JUnit extension for testing Struts actions +// within the context of the ActionServlet. +// Copyright (C) 2002 Deryl Seale +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the Apache Software License as +// published by the Apache Software Foundation; either version 1.1 +// of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// Apache Software Foundation Licens for more details. +// +// You may view the full text here: http://www.apache.org/LICENSE.txt + +package servletunit.struts; + +import junit.framework.AssertionFailedError; +import junit.framework.TestCase; +import org.apache.commons.digester.Digester; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.struts.Globals; +import org.apache.struts.action.ActionForm; +import org.apache.struts.action.ActionServlet; +import servletunit.HttpServletRequestSimulator; +import servletunit.HttpServletResponseSimulator; +import servletunit.ServletConfigSimulator; +import servletunit.ServletContextSimulator; + +import javax.servlet.http.*; +import java.io.File; +import java.io.InputStream; +import java.net.URL; + +/** + * MockStrutsTestCase is an extension of the base JUnit testcase that + * provides additional methods to aid in testing Struts Action + * objects. It uses a mock object approach to simulate a servlet + * container, and tests the execution of Action objects as they + * are actually run through the Struts ActionServlet. MockStrutsTestCase + * provides methods that set up the request path, request parameters + * for ActionForm subclasses, as well as methods that can verify + * that the correct ActionForward was used and that the proper + * ActionError messages were supplied. + * + *

+ *NOTE: By default, the Struts ActionServlet will look for the + * file WEB-INF/struts-config.xml, so you must place + * the directory that contains WEB-INF in your CLASSPATH. If + * you would like to use an alternate configuration file, please see + * the setConfigFile() method for details on how this file is located. + */ +public class MockStrutsTestCase extends TestCase { + + protected ActionServlet actionServlet; + protected HttpServletRequestSimulator request; + protected HttpServletResponseSimulator response; + protected HttpServletRequestWrapper requestWrapper; + protected HttpServletResponseWrapper responseWrapper; + protected ServletContextSimulator context; + protected ServletConfigSimulator config; + protected String actionPath; + protected boolean isInitialized = false; + protected boolean actionServletIsInitialized = false; + protected boolean requestPathSet = false; + + /** + * The set of public identifiers, and corresponding resource names, for + * the versions of the configuration file DTDs that we know about. There + * MUST be an even number of Strings in this list! + */ + protected String registrations[] = { + "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN", + "/org/apache/struts/resources/web-app_2_2.dtd", + "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN", + "/org/apache/struts/resources/web-app_2_3.dtd" + }; + + + protected static Log logger = LogFactory.getLog(MockStrutsTestCase.class); + + /** + * Default constructor. + */ + public MockStrutsTestCase() { + super(); + } + + /** + * Constructor that takes test name parameter, for backwards compatibility with older versions on JUnit. + */ + public MockStrutsTestCase(String testName) { + super(testName); + } + + /** + * A check that every method should run to ensure that the + * base class setUp method has been called. + */ + private void init() { + if (!isInitialized) + throw new AssertionFailedError("You are overriding the setUp() method without calling super.setUp(). You must call the superclass setUp() method in your TestCase subclass to ensure proper initialization."); + } + + /** + * Sets up the test fixture for this test. This method creates + * an instance of the ActionServlet, initializes it to validate + * forms and turn off debugging, and creates a mock HttpServletRequest + * and HttpServletResponse object to use in this test. + */ + protected void setUp() throws Exception { + if (logger.isDebugEnabled()) + logger.debug("Entering"); + if (actionServlet == null) + actionServlet = new ActionServlet(); + config = new ServletConfigSimulator(); + request = new HttpServletRequestSimulator(config.getServletContext()); + response = new HttpServletResponseSimulator(); + context = (ServletContextSimulator) config.getServletContext(); + requestWrapper = null; + responseWrapper = null; + isInitialized = true; + if (logger.isDebugEnabled()) + logger.debug("Exiting"); + } + + protected void tearDown() throws Exception { + ActionServlet servlet = getActionServlet(); + servlet.destroy(); + setActionServlet(servlet); + } + + /** + * Returns an HttpServletRequest object that can be used in + * this test. + */ + public HttpServletRequest getRequest() { + if (logger.isDebugEnabled()) + logger.debug("Entering"); + init(); + if (logger.isDebugEnabled()) + logger.debug("Exiting"); + return this.request; + } + + /** + * Returns a HttpServletRequestWrapper object that can be used + * in this test. Note that if {@link #setRequestWrapper} has not been + * called, this method will return an instance of + * javax.servlet.http.HttpServletRequestWrapper. + */ + public HttpServletRequestWrapper getRequestWrapper() { + if (logger.isDebugEnabled()) + logger.debug("Entering"); + init(); + if (requestWrapper == null) { + if (logger.isDebugEnabled()) + logger.debug("Exiting"); + return new HttpServletRequestWrapper(this.request); + } else { + if (logger.isDebugEnabled()) { + logger.debug("wrapper class is '" + requestWrapper.getClass() + "'"); + } + if (logger.isDebugEnabled()) + logger.debug("Exiting"); + return requestWrapper; + } + } + + /** + * Set this TestCase to use a given HttpServletRequestWrapper + * class when calling Action.execute(). Note that if this + * method is not called, then the normal HttpServletRequest + * object is used. + * + * @param wrapper an HttpServletRequestWrapper object to be + * used when calling Action.execute(). + */ + public void setRequestWrapper(HttpServletRequestWrapper wrapper) { + if (logger.isDebugEnabled()) + logger.debug("Entering - wrapper = " + wrapper); + init(); + if (wrapper == null) + throw new IllegalArgumentException("wrapper class cannot be null!"); + else { + if (wrapper.getRequest() == null) + wrapper.setRequest(this.request); + this.requestWrapper = wrapper; + } + if (logger.isDebugEnabled()) + logger.debug("Exiting"); + } + + /** + * Clears all request parameters previously set. + */ + public void clearRequestParameters() { + if (logger.isTraceEnabled()) + logger.trace("Entering"); + this.request.getParameterMap().clear(); + + // also, clear out the redirect header if it's there. + response.removeHeader("Location"); + if (logger.isTraceEnabled()) + logger.trace("Exiting"); + } + + /** + * Returns an HttpServletResponse object that can be used in + * this test. + */ + public HttpServletResponse getResponse() { + if (logger.isDebugEnabled()) + logger.debug("Entering"); + init(); + if (logger.isDebugEnabled()) + logger.debug("Exiting"); + return this.response; + } + + /** + * Returns an HttpServletResponseWrapper object that can be used in + * this test. Note that if {@link #setResponseWrapper} has not been + * called, this method will return an instance of + * javax.servlet.http.HttpServletResponseWrapper. + */ + public HttpServletResponseWrapper getResponseWrapper() { + if (logger.isDebugEnabled()) + logger.debug("Entering"); + init(); + if (responseWrapper == null) { + if (logger.isDebugEnabled()) + logger.debug("Exiting"); + return new HttpServletResponseWrapper(this.response); + } else { + if (logger.isDebugEnabled()) { + logger.debug("wrapper class is '" + responseWrapper.getClass() + "'"); + } + if (logger.isDebugEnabled()) + logger.debug("Exiting"); + return responseWrapper; + } + } + + /** + * Set this TestCase to use a given HttpServletResponseWrapper + * class when calling Action.execute(). Note that if this + * method is not called, then the normal HttpServletResponse + * object is used. + * + * @param wrapper an HttpServletResponseWrapper object to be + * used when calling Action.execute(). + */ + public void setResponseWrapper(HttpServletResponseWrapper wrapper) { + if (logger.isDebugEnabled()) + logger.debug("Entering - wrapper = " + wrapper); + init(); + if (wrapper == null) + throw new IllegalArgumentException("wrapper class cannot be null!"); + else { + if (wrapper.getResponse() == null) + wrapper.setResponse(this.response); + this.responseWrapper = wrapper; + } + if (logger.isDebugEnabled()) + logger.debug("Exiting"); + } + + /** + * Returns the mock HttpServletRequest object used in this test. This allows + * access to methods for setting up test preconditions that are otherwise + * unavailable through the normal Servlet API. + */ + public HttpServletRequestSimulator getMockRequest() { + if (logger.isTraceEnabled()) + logger.trace("Entering"); + init(); + if (logger.isTraceEnabled()) + logger.trace("Exiting"); + return this.request; + } + + /** + * Returns the mock HttpServletResponse object used in this test. This allows + * access to methods for setting up test preconditions that are otherwise + * unavailable through the normal Servlet API. + */ + public HttpServletResponseSimulator getMockResponse() { + if (logger.isTraceEnabled()) + logger.trace("Entering"); + init(); + if (logger.isTraceEnabled()) + logger.trace("Exiting"); + return this.response; + } + + /** + * Returns an HttpSession object that can be used in this + * test. + */ + public HttpSession getSession() { + if (logger.isDebugEnabled()) + logger.debug("Entering"); + init(); + if (logger.isDebugEnabled()) + logger.debug("Exiting"); + return this.request.getSession(true); + } + + /** + * Returns the ActionServlet controller used in this + * test. + * + */ + public ActionServlet getActionServlet() { + if (logger.isDebugEnabled()) + logger.debug("Entering"); + init(); + try { + if (!actionServletIsInitialized) { + if (logger.isDebugEnabled()) { + logger.debug("intializing actionServlet"); + } + this.actionServlet.init(config); + actionServletIsInitialized = true; + } + } catch (Exception e) { + logger.error("Error initializing action servlet",e); + if(e.getMessage().equals("java.lang.NullPointerException")){ + String message = "Error initializing action servlet: Unable to find /WEB-INF/web.xml. " + + "TestCase is running from " + System.getProperty("user.dir") + " directory. " + + "Context directory "; + if(this.context.getContextDirectory()==null){ + message += "has not been set. Try calling setContextDirectory() with a relative or absolute path"; + }else{ + message = message + "is " + this.context.getContextDirectory().getAbsolutePath(); + } + message = message + ". /WEB-INF/web.xml must be found under the context directory, " + + "the directory the test case is running from, or in the classpath."; + fail(message); + }else{ + throw new AssertionFailedError(e.getMessage()); + } + } + if (logger.isDebugEnabled()) + logger.debug("Exiting"); + return actionServlet; + } + + /** + * Sets the ActionServlet to be used in this test execution. This + * method should only be used if you plan to use a customized + * version different from that provided in the Struts distribution. + */ + public void setActionServlet(ActionServlet servlet) { + if (logger.isDebugEnabled()) + logger.debug("Entering - servlet = " + servlet); + init(); + if (servlet == null) + throw new AssertionFailedError("Cannot set ActionServlet to null"); + this.actionServlet = servlet; + if (logger.isDebugEnabled()) + logger.debug("Exiting"); + actionServletIsInitialized = false; + } + + /** + * Executes the Action instance to be tested. This method + * calls the ActionServlet.doPost() method to execute the + * Action instance to be tested, passing along any parameters + * set in the HttpServletRequest object. It stores any results + * for further validation. + * + * @exception AssertionFailedError if there are any execution + * errors while calling Action.execute() + * + */ + public void actionPerform() { + if (logger.isDebugEnabled()) + logger.debug("Entering"); + if(!this.requestPathSet){ + throw new IllegalStateException("You must call setRequestPathInfo() prior to calling actionPerform()."); + } + init(); + HttpServletRequest request = this.request; + HttpServletResponse response = this.response; + if (this.requestWrapper != null) + request = this.requestWrapper; + if (this.responseWrapper != null) + response = this.responseWrapper; + try { + this.getActionServlet().doPost(request,response); + }catch (NullPointerException npe) { + String message = "A NullPointerException was thrown. This may indicate an error in your ActionForm, or " + + "it may indicate that the Struts ActionServlet was unable to find struts config file. " + + "TestCase is running from " + System.getProperty("user.dir") + " directory. " + + "Context directory "; + if(this.context.getContextDirectory()==null){ + message += "has not been set. Try calling setContextDirectory() with a relative or absolute path"; + }else{ + message = message + "is " + this.context.getContextDirectory().getAbsolutePath(); + } + message = message + ". struts config file must be found under the context directory, " + + "the directory the test case is running from, or in the classpath."; + throw new ExceptionDuringTestError(message, npe); + }catch(Exception e){ + throw new ExceptionDuringTestError("An uncaught exception was thrown during actionExecute()", e); + } + if (logger.isDebugEnabled()) + logger.debug("Exiting"); + } + + /** + * Adds an HttpServletRequest parameter to be used in setting up the + * ActionForm instance to be used in this test. Each parameter added + * should correspond to an attribute in the ActionForm instance used + * by the Action instance being tested. + */ + public void addRequestParameter(String parameterName, String parameterValue) + { + if (logger.isDebugEnabled()) + logger.debug("Entering - parameterName = " + parameterName + ", parameterValue = " + parameterValue); + init(); + this.request.addParameter(parameterName,parameterValue); + if (logger.isDebugEnabled()) + logger.debug("Exiting"); + } + + /** + * Adds an HttpServletRequest parameter that is an array of String values + * to be used in setting up the ActionForm instance to be used in this test. + * Each parameter added should correspond to an attribute in the ActionForm + * instance used by the Action instance being tested. + */ + public void addRequestParameter(String parameterName, String[] parameterValues) + { + if (logger.isDebugEnabled()) + logger.debug("Entering - parameterName = " + parameterName + ", parameteValue = " + parameterValues); + init(); + this.request.addParameter(parameterName,parameterValues); + if (logger.isDebugEnabled()) + logger.debug("Exiting"); + } + + /** + * Sets the request path instructing the ActionServlet to used a + * particual ActionMapping. + * + * @param pathInfo the request path to be processed. This should + * correspond to a particular action mapping, as would normally + * appear in an HTML or JSP source file. + */ + public void setRequestPathInfo(String pathInfo) { + if (logger.isDebugEnabled()) + logger.debug("Entering - pathInfo = " + pathInfo); + init(); + this.setRequestPathInfo("",pathInfo); + if (logger.isDebugEnabled()) + logger.debug("Exiting"); + } + + /** + * Sets the request path instructing the ActionServlet to used a + * particual ActionMapping. Also sets the ServletPath property + * on the request. + * + * @param moduleName the name of the Struts sub-application with + * which this request is associated, or null if it is the default + * application. + * @param pathInfo the request path to be processed. This should + * correspond to a particular action mapping, as would normally + * appear in an HTML or JSP source file. If this request is part + * of a sub-application, the module name should not appear in the + * request path. + */ + public void setRequestPathInfo(String moduleName, String pathInfo) { + if (logger.isDebugEnabled()) + logger.debug("Entering - moduleName = " + moduleName + ", pathInfo = " + pathInfo); + init(); + this.actionPath = Common.stripActionPath(pathInfo); + if (moduleName != null) { + if (!moduleName.equals("")) { + if (!moduleName.startsWith("/")) + moduleName = "/" + moduleName; + if (!moduleName.endsWith("/")) + moduleName = moduleName + "/"; + } + if (logger.isDebugEnabled()) { + logger.debug("setting request attribute - name = " + Common.INCLUDE_SERVLET_PATH + ", value = " + moduleName); + } + this.request.setAttribute(Common.INCLUDE_SERVLET_PATH, moduleName); + } + this.request.setPathInfo(actionPath); + this.requestPathSet = true; + if (logger.isDebugEnabled()) + logger.debug("Exiting"); + } + + /** + * Sets an initialization parameter on the + * ActionServlet. Allows you to simulate an init parameter + * that would normally have been found in web.xml, + * but is not available while testing with mock objects. + * @param key the name of the initialization parameter + * @param value the value of the intialization parameter + */ + public void setInitParameter(String key, String value){ + if (logger.isDebugEnabled()) + logger.debug("Entering - key = " + key + ", value = " + value); + init(); + config.setInitParameter(key, value); + actionServletIsInitialized = false; + if (logger.isDebugEnabled()) + logger.debug("Exiting"); + } + + /** + * Sets the context directory to be used with the getRealPath() methods in + * the ServletContext and HttpServletRequest API. + * @param contextDirectory a File object representing the root context directory + * for this application. + */ + public void setContextDirectory(File contextDirectory) { + if (logger.isDebugEnabled()) + logger.debug("Entering - contextDirectory = " + contextDirectory); + init(); + context.setContextDirectory(contextDirectory); + actionServletIsInitialized = false; + if (logger.isDebugEnabled()) + logger.debug("Exiting"); + } + + /** + * Sets the location of the Struts configuration file for the default module. + * This method can take either an absolute path, or a relative path. If an + * absolute path is supplied, the configuration file will be loaded from the + * underlying filesystem; otherwise, the ServletContext loader will be used. + */ + public void setConfigFile(String pathname) { + if (logger.isDebugEnabled()) + logger.debug("Entering - pathName = " + pathname); + init(); + setConfigFile(null,pathname); + if (logger.isDebugEnabled()) + logger.debug("Exiting"); + } + + /** + * Sets the struts configuration file for a given sub-application. This method + * can take either an absolute path, or a relative path. If an absolute path + * is supplied, the configuration file will be loaded from the underlying + * filesystem; otherwise, the ServletContext loader will be used. + * + * @param moduleName the name of the sub-application, or null if this is the default application + * @param pathname the location of the configuration file for this sub-application + */ + public void setConfigFile(String moduleName, String pathname) { + if (logger.isDebugEnabled()) + logger.debug("Entering - moduleName = " + moduleName + ", pathname =" + pathname); + init(); + if (moduleName == null) + this.config.setInitParameter("config",pathname); + else + this.config.setInitParameter("config/" + moduleName,pathname); + actionServletIsInitialized = false; + if (logger.isDebugEnabled()) + logger.debug("Exiting"); + } + + /** + * Sets the location of the web.xml configuration file to be used + * to set up the servlet context and configuration for this test. + * This method supports both init-param and context-param tags, + * setting the ServletConfig and ServletContext appropriately. + * This method can take either an absolute path, or a relative path. If an + * absolute path is supplied, the configuration file will be loaded from the + * underlying filesystem; otherwise, the ServletContext loader will be used. + */ + public void setServletConfigFile(String pathname) { + if (logger.isDebugEnabled()) + logger.debug("Entering - pathname = " + pathname); + init(); + + // pull in the appropriate parts of the + // web.xml file -- first the init-parameters + Digester digester = new Digester(); + digester.push(this.config); + digester.setValidating(true); + digester.addCallMethod("web-app/servlet/init-param", "setInitParameter", 2); + digester.addCallParam("web-app/servlet/init-param/param-name", 0); + digester.addCallParam("web-app/servlet/init-param/param-value", 1); + try { + for (int i = 0; i < registrations.length; i += 2) { + URL url = context.getResource(registrations[i + 1]); + if (url != null) + digester.register(registrations[i], url.toString()); + } + InputStream input = context.getResourceAsStream(pathname); + if(input==null) + throw new AssertionFailedError("Invalid pathname: " + pathname); + digester.parse(input); + input.close(); + } catch (Exception e) { + throw new AssertionFailedError("Received an exception while loading web.xml - " + e.getClass() + " : " + e.getMessage()); + } + + // now the context parameters.. + digester = new Digester(); + digester.setValidating(true); + digester.push(this.context); + digester.addCallMethod("web-app/context-param", "setInitParameter", 2); + digester.addCallParam("web-app/context-param/param-name", 0); + digester.addCallParam("web-app/context-param/param-value", 1); + try { + for (int i = 0; i < registrations.length; i += 2) { + URL url = context.getResource(registrations[i + 1]); + if (url != null) + digester.register(registrations[i], url.toString()); + } + InputStream input = context.getResourceAsStream(pathname); + if(input==null) + throw new AssertionFailedError("Invalid pathname: " + pathname); + digester.parse(input); + input.close(); + } catch (Exception e) { + throw new AssertionFailedError("Received an exception while loading web.xml - " + e.getClass() + " : " + e.getMessage()); + } + actionServletIsInitialized = false; + if (logger.isDebugEnabled()) + logger.debug("Exiting"); + } + + /** + * Returns the forward sent to RequestDispatcher. + */ + protected String getActualForward() { + if (logger.isDebugEnabled()) + logger.debug("Entering"); + if (response.containsHeader("Location")) { + return Common.stripJSessionID(response.getHeader("Location")); + } else + try { + String strippedForward = request.getContextPath() + Common.stripJSessionID(((ServletContextSimulator) config.getServletContext()).getRequestDispatcherSimulator().getForward()); + if (logger.isDebugEnabled()) { + logger.debug("stripped forward and added context path - " + strippedForward); + } + if (logger.isDebugEnabled()) + logger.debug("Exiting"); + return strippedForward; + } catch (NullPointerException npe) { + if (logger.isDebugEnabled()) { + logger.debug("caught NullPointerException - returning null",npe); + } + return null; + } + } + + /** + * Verifies if the ActionServlet controller used this forward. + * + * @param forwardName the logical name of a forward, as defined + * in the Struts configuration file. This can either refer to a + * global forward, or one local to the ActionMapping. + * + * @exception AssertionFailedError if the ActionServlet controller + * used a different forward than forwardName after + * executing an Action object. + */ + public void verifyForward(String forwardName) throws AssertionFailedError { + if (logger.isDebugEnabled()) + logger.debug("Entering - forwardName = " + forwardName); + init(); + Common.verifyForwardPath(actionPath,forwardName,getActualForward(),false,request,config.getServletContext(),config); + if (logger.isDebugEnabled()) + logger.debug("Exiting"); + } + + /** + * Verifies if the ActionServlet controller used this actual path + * as a forward. + * + * @param forwardPath an absolute pathname to which the request + * is to be forwarded. + * + * @exception AssertionFailedError if the ActionServlet controller + * used a different forward path than forwardPath after + * executing an Action object. + */ + public void verifyForwardPath(String forwardPath) throws AssertionFailedError { + if (logger.isDebugEnabled()) + logger.debug("Entering - forwardPath = " + forwardPath); + init(); + String actualForward = getActualForward(); + if ((actualForward == null) && (forwardPath == null)) { + // actions can send null forwards, which is fine. + return; + } + + forwardPath = request.getContextPath() + forwardPath; + + if (actualForward == null) { + if (logger.isDebugEnabled()) { + logger.debug("actualForward is null - this usually means it is not mapped properly."); + } + throw new AssertionFailedError("Was expecting '" + forwardPath + "' but it appears the Action has tried to return an ActionForward that is not mapped correctly."); + } + if (logger.isDebugEnabled()) { + logger.debug("expected forward = '" + forwardPath + "' - actual forward = '" + actualForward + "'"); + } + if (!(actualForward.equals(forwardPath))) + throw new AssertionFailedError("was expecting '" + forwardPath + "' but received '" + actualForward + "'"); + if (logger.isDebugEnabled()) + logger.debug("Exiting"); + } + + /** + * Verifies if the ActionServlet controller forwarded to the defined + * input path. + * + * @exception AssertionFailedError if the ActionServlet controller + * used a different forward than the defined input path after + * executing an Action object. + */ + public void verifyInputForward() { + if (logger.isDebugEnabled()) + logger.debug("Entering"); + init(); + Common.verifyForwardPath(actionPath,null,getActualForward(),true,request,config.getServletContext(),config); + if (logger.isDebugEnabled()) + logger.debug("Exiting"); + } + + /** + * Verifies that the ActionServlet controller used this forward and Tiles definition. + * + * @param forwardName the logical name of a forward, as defined + * in the Struts configuration file. This can either refer to a + * global forward, or one local to the ActionMapping. + * + * @param definitionName the name of a Tiles definition, as defined + * in the Tiles configuration file. + * + * @exception AssertionFailedError if the ActionServlet controller + * used a different forward or tiles definition than those given after + * executing an Action object. + */ + public void verifyTilesForward(String forwardName, String definitionName) { + if (logger.isTraceEnabled()) + logger.trace("Entering - forwardName=" + forwardName + ", definitionName=" + definitionName); + init(); + Common.verifyTilesForward(actionPath,forwardName,definitionName,false,request,config.getServletContext(),config); + if (logger.isTraceEnabled()) + logger.trace("Exiting"); + } + + /** + * Verifies that the ActionServlet controller forwarded to the defined + * input Tiles definition. + * + * @param definitionName the name of a Tiles definition, as defined + * in the Tiles configuration file. + * + * @exception AssertionFailedError if the ActionServlet controller + * used a different forward than the defined input path after + * executing an Action object. + */ + public void verifyInputTilesForward(String definitionName) { + if (logger.isTraceEnabled()) + logger.trace("Entering - definitionName=" + definitionName); + init(); + Common.verifyTilesForward(actionPath,null,definitionName,true,request,config.getServletContext(),config); + if (logger.isTraceEnabled()) + logger.trace("Exiting"); + } + + /** + * Verifies if the ActionServlet controller sent these error messages. + * There must be an exact match between the provided error messages, and + * those sent by the controller, in both name and number. + * + * @param errorNames a String array containing the error message keys + * to be verified, as defined in the application resource properties + * file. + * + * @exception AssertionFailedError if the ActionServlet controller + * sent different error messages than those in errorNames + * after executing an Action object. + */ + + public void verifyActionErrors(String[] errorNames) { + if (logger.isDebugEnabled()) + logger.debug("errorNames = " + errorNames); + init(); + Common.verifyActionMessages(request,errorNames,Globals.ERROR_KEY,"error"); + if (logger.isDebugEnabled()) + logger.debug("Exiting"); + } + + + /** + * Verifies that the ActionServlet controller sent no error messages upon + * executing an Action object. + * + * @exception AssertionFailedError if the ActionServlet controller + * sent any error messages after excecuting and Action object. + */ + public void verifyNoActionErrors() { + if (logger.isDebugEnabled()) + logger.debug("Entering"); + init(); + Common.verifyNoActionMessages(request,Globals.ERROR_KEY,"error"); + if (logger.isDebugEnabled()) + logger.debug("Exiting"); + } + + /** + * Verifies if the ActionServlet controller sent these action messages. + * There must be an exact match between the provided action messages, and + * those sent by the controller, in both name and number. + * + * @param messageNames a String array containing the action message keys + * to be verified, as defined in the application resource properties + * file. + * + * @exception AssertionFailedError if the ActionServlet controller + * sent different action messages than those in messageNames + * after executing an Action object. + */ + public void verifyActionMessages(String[] messageNames) { + if (logger.isDebugEnabled()) + logger.debug("Entering - messageNames = " + messageNames); + init(); + Common.verifyActionMessages(request,messageNames,Globals.MESSAGE_KEY,"action"); + if (logger.isDebugEnabled()) + logger.debug("Exiting"); + } + + /** + * Verifies that the ActionServlet controller sent no action messages upon + * executing an Action object. + * + * @exception AssertionFailedError if the ActionServlet controller + * sent any action messages after excecuting and Action object. + */ + public void verifyNoActionMessages() { + if (logger.isDebugEnabled()) + logger.debug("Entering"); + init(); + Common.verifyNoActionMessages(request,Globals.MESSAGE_KEY,"action"); + if (logger.isDebugEnabled()) + logger.debug("Exiting"); + } + + /** + * Returns the ActionForm instance stored in either the request or session. Note + * that no form will be returned if the Action being tested cleans up the form + * instance. + * + * @ return the ActionForm instance used in this test, or null if it does not exist. + */ + public ActionForm getActionForm() { + if (logger.isDebugEnabled()) + logger.debug("Entering"); + init(); + if (logger.isDebugEnabled()) + logger.debug("Exiting"); + return Common.getActionForm(actionPath,request,context); + } + + /** + * Sets an ActionForm instance to be used in this test. The given ActionForm instance + * will be stored in the scope specified in the Struts configuration file (ie: request + * or session). Note that while this ActionForm instance is passed to the test, Struts + * will still control how it is used. In particular, it will call the ActionForm.reset() + * method, so if you override this method in your ActionForm subclass, you could potentially + * reset attributes in the form passed through this method. + * + * @param form the ActionForm instance to be used in this test. + */ + public void setActionForm(ActionForm form) { + if (logger.isDebugEnabled()) + logger.debug("Entering - form = " + form); + init(); + // make sure action servlet is intialized + getActionServlet(); + Common.setActionForm(form,request,actionPath,context); + if (logger.isDebugEnabled()) + logger.debug("Exiting"); + } + + + + +} + Index: 3rdParty_sources/strutstest/servletunit/struts/StrutsRequestWrapper.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/strutstest/servletunit/struts/Attic/StrutsRequestWrapper.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/strutstest/servletunit/struts/StrutsRequestWrapper.java 17 Aug 2012 15:17:09 -0000 1.1 @@ -0,0 +1,118 @@ +// StrutsTestCase - a JUnit extension for testing Struts actions +// within the context of the ActionServlet. +// Copyright (C) 2002 Deryl Seale +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the Apache Software License as +// published by the Apache Software Foundation; either version 1.1 +// of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// Apache Software Foundation Licens for more details. +// +// You may view the full text here: http://www.apache.org/LICENSE.txt + +package servletunit.struts; + +import org.apache.cactus.ServletURL; +import org.apache.cactus.server.HttpServletRequestWrapper; + +import java.util.*; + +/** + * A wrapper for the HttpServletRequest class. This is used in + * CactusStrutsTestCase so that we can add our own request parameters + * outside of the beginXXX and endXXX methods. This allows us to + * to use the ActionServlet as a black box, rather than mimic its + * behavior as was previously the case. + */ +public class StrutsRequestWrapper extends HttpServletRequestWrapper { + + private String pathInfo; + private String servletPath; + private Map parameters; + + public StrutsRequestWrapper(HttpServletRequestWrapper request) { + super(request,new ServletURL(request.getServerName(),request.getContextPath(),request.getServletPath(),request.getPathInfo(),request.getQueryString())); + parameters = new HashMap(); + } + + public void setPathInfo(String pathInfo) { + this.pathInfo = pathInfo; + } + + public String getPathInfo() { + if (this.pathInfo == null) + return super.getPathInfo(); + else + return this.pathInfo; + } + + public void setServletPath(String servletPath) { + this.servletPath = servletPath; + } + + public String getServletPath() { + if (this.servletPath == null) + return super.getServletPath(); + else + return this.servletPath; + } + + + public String getParameter(String name) { + String[] result = getParameterValues(name); + if ((result != null) && (result.length > 0)) { + return result[0]; + } else + return null; + } + + public String[] getParameterValues(String name) { + Object result = super.getParameterValues(name); + if ((result == null) && (parameters.containsKey(name))) { + result = parameters.get(name); + if (!(result instanceof String[])) { + String[] resultArray = { result.toString() }; + result = resultArray; + } + } + return (String[]) result; + } + + public Enumeration getParameterNames() { + Enumeration superNames = super.getParameterNames(); + List nameList = new ArrayList(parameters.keySet()); + while (superNames.hasMoreElements()) { + nameList.add(superNames.nextElement()); + } + return Collections.enumeration(nameList); + } + + public void addParameter(String name, String value) { + if ((super.getParameter(name) == null) && (name != null) && (value != null)) + parameters.put(name,value); + } + + public void addParameter(String name, String[] values) { + if ((super.getParameter(name) == null) && (name != null) && (values != null)) + parameters.put(name,values); + } + + public Map getParameterMap() { + Map result = new HashMap(); + result.putAll(super.getParameterMap()); + result.putAll(parameters); + return result; + } + + public void clearRequestParameters() { + this.parameters.clear(); +// super.request.getParameterMap().clear(); + } + +} + + Index: 3rdParty_sources/strutstest/servletunit/struts/StrutsResponseWrapper.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/strutstest/servletunit/struts/Attic/StrutsResponseWrapper.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/strutstest/servletunit/struts/StrutsResponseWrapper.java 17 Aug 2012 15:17:08 -0000 1.1 @@ -0,0 +1,199 @@ +// StrutsTestCase - a JUnit extension for testing Struts actions +// within the context of the ActionServlet. +// Copyright (C) 2002 Deryl Seale +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the Apache Software License as +// published by the Apache Software Foundation; either version 1.1 +// of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// Apache Software Foundation Licens for more details. +// +// You may view the full text here: http://www.apache.org/LICENSE.txt + +package servletunit.struts; + +import javax.servlet.ServletOutputStream; +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.Locale; + +/** + * A wrapper for the HttpServletResponse class. This is used in + * CactusStrutsTestCase so that we can retrieve the redirect URL + * set by the ActionServlet in processing an action. This allows + * us to use the ActionServlet as a black box, rather than mimic + * its behavior as was previously the case. + */ +public class StrutsResponseWrapper implements HttpServletResponse +{ + + private HttpServletResponse response; + private String redirectLocation; + + public StrutsResponseWrapper(HttpServletResponse response) { + this.response = response; + } + + public void addCookie(Cookie cookie) + { + this.response.addCookie(cookie); + } + + public void addDateHeader(String name, long date) + { + this.response.addDateHeader(name,date); + } + + public void addHeader(String name, String value) + { + this.response.addHeader(name,value); + } + + public void addIntHeader(String name, int value) + { + this.response.addIntHeader(name,value); + } + + public boolean containsHeader(String name) + { + return this.response.containsHeader(name); + } + + public String encodeRedirectUrl(String url) + { + return this.response.encodeRedirectUrl(url); + } + + public String encodeRedirectURL(String url) + { + return this.response.encodeRedirectURL(url); + } + + public String encodeUrl(String url) + { + return this.response.encodeUrl(url); + } + + public String encodeURL(String url) + { + return this.response.encodeURL(url); + } + + public void flushBuffer() throws IOException + { + this.response.flushBuffer(); + } + + public int getBufferSize() + { + return this.response.getBufferSize(); + } + + public String getCharacterEncoding() + { + return this.response.getCharacterEncoding(); + } + + public Locale getLocale() + { + return this.response.getLocale(); + } + + public ServletOutputStream getOutputStream() throws IOException + { + return this.response.getOutputStream(); + } + + public PrintWriter getWriter() throws IOException + { + return this.response.getWriter(); + } + + public boolean isCommitted() + { + return this.response.isCommitted(); + } + + public void reset() + { + this.response.reset(); + } + + public void resetBuffer() + { + this.response.resetBuffer(); + } + + public void sendError(int sc) throws IOException + { + this.response.sendError(sc); + } + + public void sendError(int sc, String msg) throws IOException + { + this.response.sendError(sc,msg); + } + + public void sendRedirect(String location) throws IOException + { + this.redirectLocation = location; + this.response.sendRedirect(location); + } + + public void setBufferSize(int size) + { + this.response.setBufferSize(size); + } + + public void setContentLength(int len) + { + this.response.setContentLength(len); + } + + public void setContentType(String type) + { + this.response.setContentType(type); + } + + public void setDateHeader(String name, long date) + { + this.response.setDateHeader(name,date); + } + + public void setHeader(String name, String value) + { + this.response.setHeader(name,value); + } + + public void setIntHeader(String name, int value) + { + this.response.setIntHeader(name,value); + } + + public void setStatus(int sc) + { + this.response.setStatus(sc); + } + + public void setStatus(int sc, String sm) + { + this.response.setStatus(sc,sm); + } + + public void setLocale(Locale loc) + { + this.response.setLocale(loc); + } + + public String getRedirectLocation() { + return this.redirectLocation; + } + +} + Index: 3rdParty_sources/strutstest/servletunit/struts/StrutsServletConfigWrapper.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/strutstest/servletunit/struts/Attic/StrutsServletConfigWrapper.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/strutstest/servletunit/struts/StrutsServletConfigWrapper.java 17 Aug 2012 15:17:09 -0000 1.1 @@ -0,0 +1,47 @@ +// StrutsTestCase - a JUnit extension for testing Struts actions +// within the context of the ActionServlet. +// Copyright (C) 2002 Deryl Seale +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the Apache Software License as +// published by the Apache Software Foundation; either version 1.1 +// of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// Apache Software Foundation Licens for more details. +// +// You may view the full text here: http://www.apache.org/LICENSE.txt + +package servletunit.struts; + +import org.apache.cactus.server.ServletConfigWrapper; + +import javax.servlet.ServletConfig; +import javax.servlet.ServletContext; + +/** + * A wrapper for the ServletConfig class. This is used in + * CactusStrutsTestCase so that we can use out own ServletContext + * wrapper class. This allows us to to use the ActionServlet + * as a black box, rather than mimic its behavior as was previously + * the case. + */ +public class StrutsServletConfigWrapper extends ServletConfigWrapper { + + private ServletContext context; + + public StrutsServletConfigWrapper(ServletConfig config) { + super(config); + } + + public ServletContext getServletContext() { + return this.context; + } + + public void setServletContext(ServletContext context) { + this.context = context; + } + +} Index: 3rdParty_sources/strutstest/servletunit/struts/StrutsServletContextWrapper.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/strutstest/servletunit/struts/Attic/StrutsServletContextWrapper.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/strutstest/servletunit/struts/StrutsServletContextWrapper.java 17 Aug 2012 15:17:09 -0000 1.1 @@ -0,0 +1,97 @@ +// StrutsTestCase - a JUnit extension for testing Struts actions +// within the context of the ActionServlet. +// Copyright (C) 2002 Deryl Seale +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the Apache Software License as +// published by the Apache Software Foundation; either version 1.1 +// of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// Apache Software Foundation Licens for more details. +// +// You may view the full text here: http://www.apache.org/LICENSE.txt + +package servletunit.struts; + +import org.apache.cactus.server.ServletContextWrapper; +import servletunit.RequestDispatcherSimulator; + +import javax.servlet.RequestDispatcher; +import javax.servlet.ServletContext; +import java.net.URL; +import java.net.MalformedURLException; +import java.io.File; +import java.io.InputStream; +import java.io.FileInputStream; +import java.io.FileNotFoundException; + +/** + * A wrapper for the ServletContext class. This is used in + * CactusStrutsTestCase so that we can retrieve the forward + * processed by the ActionServlet and use absolute paths + * for Struts resources. This allows us to to use + * the ActionServlet as a black box, rather than mimic its + * behavior as was previously the case. + */ +public class StrutsServletContextWrapper extends ServletContextWrapper { + + boolean processRequest = false; + private String dispatchedResource; + + public StrutsServletContextWrapper(ServletContext context) { + super(context); + } + + public void setProcessRequest(boolean flag) { + this.processRequest = flag; + } + + public RequestDispatcher getRequestDispatcher(String path) { + dispatchedResource = path; + if (!processRequest) + return new RequestDispatcherSimulator(path); + else + return super.getRequestDispatcher(path); + } + + public String getForward() { + return dispatchedResource; + } + + /** + * Override the getResource method to look for resources in the file system, allowing + * the use of absolute paths for Struts configuration files. If the resource path exists + * in the file system, this method will return a URL based on the supplied path; otherwise, + * it defers to the ServletContext loader. + */ + public URL getResource(String pathname) throws MalformedURLException { + File file = new File(pathname); + if (file.exists()) + return file.toURL(); + else + return super.getResource(pathname); + } + + /** + * Override the getResourceAsStream method to look for resources in the file system, allowing + * the use of absolute paths for Struts configuration files. If the resource path exists + * in the file system, this method will return a URL based on the supplied path; otherwise, + * it defers to the ServletContext loader. + */ + public InputStream getResourceAsStream(String pathname) { + File file = new File(pathname); + if (file.exists()) + try { + return new FileInputStream(file); + } catch (FileNotFoundException e) { + return super.getResourceAsStream(pathname); + } + else + return super.getResourceAsStream(pathname); + } + +} + Index: 3rdParty_sources/strutstest/servletunit/struts/TestPathFunctions.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/strutstest/servletunit/struts/Attic/TestPathFunctions.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/strutstest/servletunit/struts/TestPathFunctions.java 17 Aug 2012 15:17:09 -0000 1.1 @@ -0,0 +1,24 @@ +package servletunit.struts; + +import junit.framework.TestCase; + +public class TestPathFunctions extends TestCase { + + public void testStripSessionId() { + String path = "/my/path;jsessionid=123456789"; + path = Common.stripJSessionID(path); + assertEquals("/my/path",path); + } + + public void testStripLongSessionId() { + String path = "/my/path;jsessionid=99999999999999999999999999999999999999999999999999999999999"; + path = Common.stripJSessionID(path); + assertEquals("/my/path",path); + } + + public void testStripSessionIdWithQueryString() { + String path = "/my/path;jsessionid=123456789?param=\"true\""; + path = Common.stripJSessionID(path); + assertEquals("/my/path?param=\"true\"",path); + } +} Index: 3rdParty_sources/strutstest/servletunit/struts/2_2/CactusStrutsTestCase.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/strutstest/servletunit/struts/2_2/Attic/CactusStrutsTestCase.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/strutstest/servletunit/struts/2_2/CactusStrutsTestCase.java 17 Aug 2012 15:17:19 -0000 1.1 @@ -0,0 +1,725 @@ +// StrutsTestCase - a JUnit extension for testing Struts actions +// within the context of the ActionServlet. +// Copyright (C) 2002 Deryl Seale +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the Apache Software License as +// published by the Apache Software Foundation; either version 1.1 +// of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// Apache Software Foundation Licens for more details. +// +// You may view the full text here: http://www.apache.org/LICENSE.txt + +package servletunit.struts; + +import junit.framework.AssertionFailedError; +import org.apache.cactus.ServletTestCase; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.struts.Globals; +import org.apache.struts.action.ActionForm; +import org.apache.struts.action.ActionServlet; + +import javax.servlet.ServletContext; +import javax.servlet.ServletException; +import javax.servlet.ServletConfig; +import javax.servlet.http.*; +import java.util.Enumeration; +import java.util.List; +import java.util.ArrayList; +import java.util.Iterator; + +/** + * CactusStrutsTestCase is an extension of the Cactus ServletTestCase + * base class that provides additional methods to aid in testing + * Struts Action objects. It uses an in-container approach to run + * the servlet container, and tests the execution of Action objects as they + * are actually run through the Struts ActionServlet. CactusStrutsTestCase + * provides methods that set up the request path, request parameters + * for ActionForm subclasses, as well as methods that can verify + * that the correct ActionForward was used and that the proper + * ActionError messages were supplied. + *
+ *
+ * Please note that this class is meant to run in the Cactus + * framework, and you must configure your test environment + * accordingly. Please see http://jakarta.apache.org/cactus + * for more details. + * + */ +public class CactusStrutsTestCase extends ServletTestCase { + + protected ActionServlet actionServlet; + protected boolean isInitialized = false; + protected boolean actionServletIsInitialized = false; + protected boolean requestPathIsSet = false; + protected String moduleName; + protected String servletMapping = "*.do"; + + protected static Log logger = LogFactory.getLog(CactusStrutsTestCase.class); + + /** + * Default constructor. + */ + public CactusStrutsTestCase() { + super(); + } + + /** + * Constructor that takes test name parameter, for backwards compatibility with older versions on JUnit. + */ + public CactusStrutsTestCase(String testName) { + super(testName); + } + + /** + * A check that every method should run to ensure that the + * base class setUp method has been called. + */ + private void init() { + if (!isInitialized) { + throw new AssertionFailedError("You are overriding the setUp() method without calling super.setUp(). You must call the superclass setUp() and tearDown() methods in your TestCase subclass to ensure proper initialization."); + } + } + + /** + * Sets up the test fixture for this test. This method creates + * an instance of the ActionServlet, initializes it to validate + * forms and turn off debugging, and clears all other parameters. + */ + protected void setUp() throws Exception { + if (logger.isDebugEnabled()) + logger.debug("Entering"); + try { + + if (actionServlet == null) + actionServlet = new ActionServlet(); + ServletContext servletContext = new StrutsServletContextWrapper(this.config.getServletContext()); + this.config = new StrutsServletConfigWrapper(this.config); + ((StrutsServletConfigWrapper) this.config).setServletContext(servletContext); + this.request = new StrutsRequestWrapper(this.request); + this.response = new StrutsResponseWrapper(this.response); + isInitialized = true; + if (logger.isDebugEnabled()) + logger.debug("Exiting"); + } catch (Exception e) { + if (logger.isDebugEnabled()) + logger.debug(e); + throw new AssertionFailedError("Error trying to set up test fixture: " + e.getClass() + " - " + e.getMessage()); + } + } + + /** + * Sets the servlet mapping used to map requests to the Struts controller. This is used to restore + * proper setting after the test has been executed. By default, the stanard "*.do" mapping will be + * restored, so only use this method for non-standard servlet mappings. + * @param servletMapping + */ + public void setServletMapping(String servletMapping) { + this.servletMapping = servletMapping; + } + + protected void tearDown () throws Exception { + if (logger.isTraceEnabled()) + logger.trace("Entering"); + + // remove all RequestProcessor instances from context + // so that web application will function normally. + ServletContext context = this.config.getServletContext(); + List nameList = new ArrayList(); + Enumeration attributeNames = context.getAttributeNames(); + while (attributeNames.hasMoreElements()) { + String name = (String) attributeNames.nextElement(); + if (name.startsWith(Globals.REQUEST_PROCESSOR_KEY)) + nameList.add(name); + } + + // restore the original servlet mapping + ServletConfig originalConfig = ((org.apache.cactus.server.ServletConfigWrapper) this.config).getOriginalConfig(); + ServletContext originalContext = originalConfig.getServletContext(); + originalContext.setAttribute(Globals.SERVLET_KEY,servletMapping); + ((StrutsServletConfigWrapper) config).setServletContext(originalContext); + + + for (Iterator iterator = nameList.iterator(); iterator.hasNext();) { + context.removeAttribute((String) iterator.next()); + } + + if (logger.isTraceEnabled()) + logger.trace("Exiting"); + } + + /** + * Returns an HttpServletRequest object that can be used in + * this test. + */ + public HttpServletRequest getRequest() { + if (logger.isDebugEnabled()) + logger.debug("Entering"); + init(); + if (logger.isDebugEnabled()) + logger.debug("Exiting"); + return this.request; + } + + /** + * Returns an HttpServletResponse object that can be used in + * this test. + */ + public HttpServletResponse getResponse() { + if (logger.isDebugEnabled()) + logger.debug("Entering"); + init(); + if (logger.isDebugEnabled()) + logger.debug("Exiting"); + return this.response; + } + + /** + * Returns an HttpSession object that can be used in this + * test. + */ + public HttpSession getSession() { + if (logger.isDebugEnabled()) + logger.debug("Entering"); + init(); + if (logger.isDebugEnabled()) + logger.debug("Exiting"); + return this.session; + } + + /** + * Adds an HttpServletRequest parameter to be used in setting up the + * ActionForm instance to be used in this test. Each parameter added + * should correspond to an attribute in the ActionForm instance used + * by the Action instance being tested. + */ + public void addRequestParameter(String parameterName, String parameterValue) + { + if (logger.isDebugEnabled()) + logger.debug("Entering - paramaterName = " + parameterName + ", parameterValue = " + parameterValue); + init(); + ((StrutsRequestWrapper) this.request).addParameter(parameterName,parameterValue); + if (logger.isDebugEnabled()) + logger.debug("Exiting"); + } + + /** + * Adds an HttpServletRequest parameter that is an array of String values + * to be used in setting up the ActionForm instance to be used in this test. + * Each parameter added should correspond to an attribute in the ActionForm + * instance used by the Action instance being tested. + */ + public void addRequestParameter(String parameterName, String[] parameterValues) + { + if (logger.isDebugEnabled()) + logger.debug("Entering - paramaterName = " + parameterName + ", parameterValue = " + parameterValues); + init(); + ((StrutsRequestWrapper) this.request).addParameter(parameterName,parameterValues); + if (logger.isDebugEnabled()) + logger.debug("Exiting"); + } + + /** + * Clears all request parameters previously set. NOTE: This will not clear + * parameters set using Cactus beginXXX methods! + */ + public void clearRequestParameters() { + init(); + ((StrutsRequestWrapper) request).clearRequestParameters(); + } + + /** + * Sets the request path instructing the ActionServlet to used a + * particual ActionMapping. + * + * @param pathInfo the request path to be processed. This should + * correspond to a particular action mapping, as would normally + * appear in an HTML or JSP source file. + */ + public void setRequestPathInfo(String pathInfo) { + if (logger.isDebugEnabled()) + logger.debug("Entering - pathInfo = " + pathInfo); + init(); + this.setRequestPathInfo("",pathInfo); + if (logger.isDebugEnabled()) + logger.debug("Exiting"); + } + + + /** + * Sets the request path instructing the ActionServlet to used a + * particual ActionMapping. Also sets the ServletPath property + * on the request. + * + * @param moduleName the name of the Struts sub-application with + * which this request is associated, or null if it is the default + * application. + * @param pathInfo the request path to be processed. This should + * correspond to a particular action mapping, as would normally + * appear in an HTML or JSP source file. If this request is part + * of a sub-application, the module name should not appear in the + * request path. + */ + public void setRequestPathInfo(String moduleName, String pathInfo) { + if (logger.isDebugEnabled()) + logger.debug("Entering - moduleName = " + moduleName + ", pathInfo = " + pathInfo); + init(); + ((StrutsRequestWrapper) this.request).setPathInfo(Common.stripActionPath(pathInfo)); + if (moduleName != null) { + if (!moduleName.equals("")) { + if (!moduleName.startsWith("/")) + moduleName = "/" + moduleName; + if (!moduleName.endsWith("/")) + moduleName = moduleName + "/"; + } + if (logger.isDebugEnabled()) { + logger.debug("setting request.ServletPath value = " + moduleName); + } + ((StrutsRequestWrapper) this.request).setServletPath(moduleName); + this.requestPathIsSet = true; + } + if (logger.isDebugEnabled()) + logger.debug("Exiting"); + } + + /** + * Sets an initialization parameter on the + * ActionServlet. Allows you to simulate an init parameter + * that would normally have been found in web.xml. + * @param key the name of the initialization parameter + * @param value the value of the intialization parameter + */ + public void setInitParameter(String key, String value){ + if (logger.isDebugEnabled()) + logger.debug("Entering - key = " + key + ", value = " + value); + this.config.setInitParameter(key, value); + this.actionServletIsInitialized = false; + if (logger.isDebugEnabled()) + logger.debug("Exiting"); + } + + /** + * Sets the location of the Struts configuration file for the default module. + * This method can take either an absolute path, or a relative path. If an + * absolute path is supplied, the configuration file will be loaded from the + * underlying filesystem; otherwise, the ServletContext loader will be used. + */ + public void setConfigFile(String pathname) { + if (logger.isDebugEnabled()) + logger.debug("Entering - pathname = " + pathname); + init(); + setConfigFile(null,pathname); + if (logger.isDebugEnabled()) + logger.debug("Exiting"); + } + + /** + * Sets the struts configuration file for a given sub-application. + * This method can take either an absolute path, or a relative path. If an + * absolute path is supplied, the configuration file will be loaded from the + * underlying filesystem; otherwise, the ServletContext loader will be used. + * + * @param moduleName the name of the sub-application, or null if this is the default application + * @param pathname the location of the configuration file for this sub-application + */ + public void setConfigFile(String moduleName, String pathname) { + if (logger.isDebugEnabled()) + logger.debug("Entering - moduleName = " + moduleName + ", pathname = " + pathname); + init(); + if (moduleName == null) + this.config.setInitParameter("config",pathname); + else + this.config.setInitParameter("config/" + moduleName,pathname); + actionServletIsInitialized = false; + if (logger.isDebugEnabled()) + logger.debug("Exiting"); + } + + /** + * Returns the ActionServlet controller used in this + * test. + * + */ + public ActionServlet getActionServlet() { + if (logger.isDebugEnabled()) + logger.debug("Entering"); + init(); + try { + if (!actionServletIsInitialized) { + // the RequestProcessor holds on to the ServletContext, so + // we need to ensure that it is replaced for each test. + ServletContext context = config.getServletContext(); + String name = "org.apache.struts.action.REQUEST_PROCESSOR"; + + // remove request processor for default module + Object obj = context.getAttribute(name); + if (obj != null) { + config.getServletContext().removeAttribute(name); + } + + // remove request processor for sub-applications, if used. + // todo: this seems pretty redundant.. may want to make this cleaner. + String moduleName = request.getServletPath() != null ? request.getServletPath() : ""; + + if (moduleName.endsWith("/")) + moduleName = moduleName.substring(0,moduleName.lastIndexOf("/")); + + obj = context.getAttribute(name + moduleName); + if (obj != null) { + config.getServletContext().removeAttribute(name + moduleName); + } + + this.actionServlet.init(config); + actionServletIsInitialized = true; + } + if (logger.isDebugEnabled()) + logger.debug("Exiting"); + return this.actionServlet; + } catch (ServletException e) { + if (logger.isDebugEnabled()) + logger.debug("Error in getActionServlet()",e.getRootCause()); + throw new AssertionFailedError("Error while initializing ActionServlet: " + e.getMessage()); + } + } + + /** + * Sets the ActionServlet to be used in this test execution. This + * method should only be used if you plan to use a customized + * version different from that provided in the Struts distribution. + */ + public void setActionServlet(ActionServlet servlet) { + if (logger.isDebugEnabled()) + logger.debug("Entering - servlet = " + servlet); + init(); + if (servlet == null) + throw new AssertionFailedError("Cannot set ActionServlet to null"); + this.actionServlet = servlet; + actionServletIsInitialized = false; + if (logger.isDebugEnabled()) + logger.debug("Exiting"); + } + + /** + * Executes the Action instance to be tested. This method initializes + * the ActionServlet, sets up and optionally validates the ActionForm + * bean associated with the Action to be tested, and then calls the + * Action.execute() method. Results are stored for further validation. + * + * @exception AssertionFailedError if there are any execution + * errors while calling Action.execute() or ActionForm.validate(). + * + */ + public void actionPerform() { + if (logger.isDebugEnabled()) + logger.debug("Entering"); + if(!this.requestPathIsSet){ + throw new IllegalStateException("You must call setRequestPathInfo() prior to calling actionPerform()."); + } + init(); + try { + HttpServletRequest request = this.request; + HttpServletResponse response = this.response; + // make sure errors are cleared from last test. + request.removeAttribute(Globals.ERROR_KEY); + request.removeAttribute(Globals.MESSAGE_KEY); + + ActionServlet actionServlet = this.getActionServlet(); + actionServlet.doPost(request,response); + if (logger.isDebugEnabled()) + logger.debug("Exiting"); + } catch (NullPointerException npe) { + String message = "A NullPointerException was thrown. This may indicate an error in your ActionForm, or " + + "it may indicate that the Struts ActionServlet was unable to find struts config file. " + + "TestCase is running from " + System.getProperty("user.dir") + " directory."; + throw new ExceptionDuringTestError(message, npe); + } catch(Exception e){ + throw new ExceptionDuringTestError("An uncaught exception was thrown during actionExecute()", e); + } + } + + /** + * Returns the forward sent to RequestDispatcher. + */ + protected String getActualForward() { + if (logger.isDebugEnabled()) + logger.debug("Entering"); + if (response.containsHeader("Location")) { + return Common.stripJSessionID(((StrutsResponseWrapper) response).getRedirectLocation()); + } else { + String forward = ((StrutsServletContextWrapper) this.actionServlet.getServletContext()).getForward(); + if (logger.isDebugEnabled()) { + logger.debug("actual forward = " + forward); + } + if (forward == null) { + if (logger.isDebugEnabled()) + logger.debug("Exiting"); + return null; + } else { + String temp = Common.stripJSessionID(forward); + if (!temp.startsWith("/")) + temp = "/" + temp; + String strippedForward = request.getContextPath() + temp; + if (logger.isDebugEnabled()) { + logger.debug("stripped forward and added context path = " + strippedForward); + } + if (logger.isDebugEnabled()) + logger.debug("Exiting"); + return strippedForward; + } + } + + } + + /** + * Verifies if the ActionServlet controller used this forward. + * + * @param forwardName the logical name of a forward, as defined + * in the Struts configuration file. This can either refer to a + * global forward, or one local to the ActionMapping. + * + * @exception AssertionFailedError if the ActionServlet controller + * used a different forward than forwardName after + * executing an Action object. + */ + public void verifyForward(String forwardName) throws AssertionFailedError { + if (logger.isDebugEnabled()) + logger.debug("Entering - forwardName = " + forwardName); + init(); + Common.verifyForwardPath(request.getPathInfo(),forwardName,getActualForward(),false,request,config.getServletContext(),config); + if (logger.isDebugEnabled()) + logger.debug("Exiting"); + } + + /** + * Verifies if the ActionServlet controller used this actual path + * as a forward. + * + * @param forwardPath an absolute pathname to which the request + * is to be forwarded. + * + * @exception AssertionFailedError if the ActionServlet controller + * used a different forward path than forwardPath after + * executing an Action object. + */ + public void verifyForwardPath(String forwardPath) throws AssertionFailedError { + if (logger.isDebugEnabled()) + logger.debug("Entering - forwardPath = " + forwardPath); + init(); + String actualForward = getActualForward(); + + if ((actualForward == null) && (forwardPath == null)) { +// actions can return null forwards. + return; + } + + forwardPath = request.getContextPath() + forwardPath; + + if (actualForward == null) { + if (logger.isDebugEnabled()) { + logger.debug("actualForward is null - this usually means it is not mapped properly."); + } + throw new AssertionFailedError("Was expecting '" + forwardPath + "' but it appears the Action has tried to return an ActionForward that is not mapped correctly."); + } + if (logger.isDebugEnabled()) { + logger.debug("expected forward = '" + forwardPath + "' - actual forward = '" + actualForward + "'"); + } + if (!(actualForward.equals(forwardPath))) + throw new AssertionFailedError("was expecting '" + forwardPath + "' but received '" + actualForward + "'"); + if (logger.isDebugEnabled()) + logger.debug("Exiting"); + } + + /** + * Verifies if the ActionServlet controller forwarded to the defined + * input path. + * + * @exception AssertionFailedError if the ActionServlet controller + * used a different forward than the defined input path after + * executing an Action object. + */ + public void verifyInputForward() { + if (logger.isDebugEnabled()) + logger.debug("Entering"); + init(); + Common.verifyForwardPath(request.getPathInfo(),null,getActualForward(),true,request,config.getServletContext(),config); + if (logger.isDebugEnabled()) + logger.debug("Exiting"); + } + + /** + * Verifies that the ActionServlet controller used this forward and Tiles definition. + * + * @param forwardName the logical name of a forward, as defined + * in the Struts configuration file. This can either refer to a + * global forward, or one local to the ActionMapping. + * + * @param definitionName the name of a Tiles definition, as defined + * in the Tiles configuration file. + * + * @exception AssertionFailedError if the ActionServlet controller + * used a different forward or tiles definition than those given after + * executing an Action object. + */ + public void verifyTilesForward(String forwardName, String definitionName) { + if (logger.isTraceEnabled()) + logger.trace("Entering - forwardName=" + forwardName + ", definitionName=" + definitionName); + init(); + Common.verifyTilesForward(request.getPathInfo(),forwardName,definitionName,false,request,config.getServletContext(),config); + if (logger.isTraceEnabled()) + logger.trace("Exiting"); + } + + /** + * Verifies that the ActionServlet controller forwarded to the defined + * input Tiles definition. + * + * @param definitionName the name of a Tiles definition, as defined + * in the Tiles configuration file. + * + * @exception AssertionFailedError if the ActionServlet controller + * used a different forward than the defined input path after + * executing an Action object. + */ + public void verifyInputTilesForward(String definitionName) { + if (logger.isTraceEnabled()) + logger.trace("Entering - defintionName=" + definitionName); + init(); + Common.verifyTilesForward(request.getPathInfo(),null,definitionName,true,request,config.getServletContext(),config); + if (logger.isTraceEnabled()) + logger.trace("Exiting"); + } + + /** + * Verifies if the ActionServlet controller sent these error messages. + * There must be an exact match between the provided error messages, and + * those sent by the controller, in both name and number. + * + * @param errorNames a String array containing the error message keys + * to be verified, as defined in the application resource properties + * file. + * + * @exception AssertionFailedError if the ActionServlet controller + * sent different error messages than those in errorNames + * after executing an Action object. + */ + + public void verifyActionErrors(String[] errorNames) { + if (logger.isDebugEnabled()) + logger.debug("Entering - errorNames = " + errorNames); + init(); + Common.verifyActionMessages(request,errorNames,Globals.ERROR_KEY,"error"); + if (logger.isDebugEnabled()) + logger.debug("Exiting"); + } + + /** + * Verifies that the ActionServlet controller sent no error messages upon + * executing an Action object. + * + * @exception AssertionFailedError if the ActionServlet controller + * sent any error messages after excecuting and Action object. + */ + public void verifyNoActionErrors() { + if (logger.isDebugEnabled()) + logger.debug("Entering"); + init(); + Common.verifyNoActionMessages(request,Globals.ERROR_KEY,"error"); + if (logger.isDebugEnabled()) + logger.debug("Exiting"); + } + + /** + * Verifies if the ActionServlet controller sent these action messages. + * There must be an exact match between the provided action messages, and + * those sent by the controller, in both name and number. + * + * @param messageNames a String array containing the action message keys + * to be verified, as defined in the application resource properties + * file. + * + * @exception AssertionFailedError if the ActionServlet controller + * sent different action messages than those in messageNames + * after executing an Action object. + */ + public void verifyActionMessages(String[] messageNames) { + if (logger.isDebugEnabled()) + logger.debug("Entering - messageNames = " + messageNames); + init(); + Common.verifyActionMessages(request,messageNames,Globals.MESSAGE_KEY,"action"); + if (logger.isDebugEnabled()) + logger.debug("Exiting"); + } + + /** + * Verifies that the ActionServlet controller sent no action messages upon + * executing an Action object. + * + * @exception AssertionFailedError if the ActionServlet controller + * sent any action messages after excecuting and Action object. + */ + public void verifyNoActionMessages() { + if (logger.isDebugEnabled()) + logger.debug("Entering"); + init(); + Common.verifyNoActionMessages(request,Globals.MESSAGE_KEY,"action"); + if (logger.isDebugEnabled()) + logger.debug("Exiting"); + } + + /** + * Returns the ActionForm instance stored in either the request or session. Note + * that no form will be returned if the Action being tested cleans up the form + * instance. + * + * @ return the ActionForm instance used in this test, or null if it does not exist. + */ + public ActionForm getActionForm() { + if (logger.isDebugEnabled()) + logger.debug("Entering"); + init(); + if (logger.isDebugEnabled()) + logger.debug("Exiting"); + return Common.getActionForm(request.getPathInfo(),request,config.getServletContext()); + } + + /** + * Sets an ActionForm instance to be used in this test. The given ActionForm instance + * will be stored in the scope specified in the Struts configuration file (ie: request + * or session). Note that while this ActionForm instance is passed to the test, Struts + * will still control how it is used. In particular, it will call the ActionForm.reset() + * method, so if you override this method in your ActionForm subclass, you could potentially + * reset attributes in the form passed through this method. + * + * @param form the ActionForm instance to be used in this test. + */ + public void setActionForm(ActionForm form) { + if (logger.isDebugEnabled()) + logger.debug("Entering - form = " + form); + init(); + // make sure ActionServlet is initialized. + Common.setActionForm(form,request,request.getPathInfo(),config.getServletContext()); + if (logger.isDebugEnabled()) + logger.debug("Exiting"); + } + + /** + * Instructs StrutsTestCase to fully process a forward request. By default, StrutsTestCase + * stops processing a request as soon as the forward path has been collected, in order to avoid + * side effects; calling this method overrides this behavior. + * @param flag set to true to fully process forward requests + */ + public void processRequest(boolean flag) { + if (logger.isTraceEnabled()) + logger.trace("Entering - flag=" + flag); + ((StrutsServletContextWrapper) this.config.getServletContext()).setProcessRequest(flag); + if (logger.isTraceEnabled()) + logger.trace("Exiting"); + } + +} + Index: 3rdParty_sources/strutstest/servletunit/struts/2_2/MockStrutsTestCase.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/strutstest/servletunit/struts/2_2/Attic/MockStrutsTestCase.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/strutstest/servletunit/struts/2_2/MockStrutsTestCase.java 17 Aug 2012 15:17:19 -0000 1.1 @@ -0,0 +1,793 @@ +// StrutsTestCase - a JUnit extension for testing Struts actions +// within the context of the ActionServlet. +// Copyright (C) 2002 Deryl Seale +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the Apache Software License as +// published by the Apache Software Foundation; either version 1.1 +// of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// Apache Software Foundation Licens for more details. +// +// You may view the full text here: http://www.apache.org/LICENSE.txt + +package servletunit.struts; + +import junit.framework.AssertionFailedError; +import junit.framework.TestCase; +import org.apache.commons.digester.Digester; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.struts.Globals; +import org.apache.struts.action.ActionForm; +import org.apache.struts.action.ActionServlet; +import servletunit.HttpServletRequestSimulator; +import servletunit.HttpServletResponseSimulator; +import servletunit.ServletConfigSimulator; +import servletunit.ServletContextSimulator; + +import javax.servlet.http.*; +import java.io.File; +import java.io.InputStream; +import java.net.URL; + +/** + * MockStrutsTestCase is an extension of the base JUnit testcase that + * provides additional methods to aid in testing Struts Action + * objects. It uses a mock object approach to simulate a servlet + * container, and tests the execution of Action objects as they + * are actually run through the Struts ActionServlet. MockStrutsTestCase + * provides methods that set up the request path, request parameters + * for ActionForm subclasses, as well as methods that can verify + * that the correct ActionForward was used and that the proper + * ActionError messages were supplied. + * + *

+ *NOTE: By default, the Struts ActionServlet will look for the + * file WEB-INF/struts-config.xml, so you must place + * the directory that contains WEB-INF in your CLASSPATH. If + * you would like to use an alternate configuration file, please see + * the setConfigFile() method for details on how this file is located. + */ +public class MockStrutsTestCase extends TestCase { + + protected ActionServlet actionServlet; + protected HttpServletRequestSimulator request; + protected HttpServletResponseSimulator response; + protected ServletContextSimulator context; + protected ServletConfigSimulator config; + protected String actionPath; + protected boolean isInitialized = false; + protected boolean actionServletIsInitialized = false; + protected boolean requestPathSet = false; + + /** + * The set of public identifiers, and corresponding resource names, for + * the versions of the configuration file DTDs that we know about. There + * MUST be an even number of Strings in this list! + */ + protected String registrations[] = { + "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN", + "/org/apache/struts/resources/web-app_2_2.dtd", + "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN", + "/org/apache/struts/resources/web-app_2_3.dtd" + }; + + + protected static Log logger = LogFactory.getLog(MockStrutsTestCase.class); + + /** + * Default constructor. + */ + public MockStrutsTestCase() { + super(); + } + + /** + * Constructor that takes test name parameter, for backwards compatibility with older versions on JUnit. + */ + public MockStrutsTestCase(String testName) { + super(testName); + } + + /** + * A check that every method should run to ensure that the + * base class setUp method has been called. + */ + private void init() { + if (!isInitialized) + throw new AssertionFailedError("You are overriding the setUp() method without calling super.setUp(). You must call the superclass setUp() method in your TestCase subclass to ensure proper initialization."); + } + + /** + * Sets up the test fixture for this test. This method creates + * an instance of the ActionServlet, initializes it to validate + * forms and turn off debugging, and creates a mock HttpServletRequest + * and HttpServletResponse object to use in this test. + */ + protected void setUp() throws Exception { + if (logger.isDebugEnabled()) + logger.debug("Entering"); + if (actionServlet == null) + actionServlet = new ActionServlet(); + config = new ServletConfigSimulator(); + request = new HttpServletRequestSimulator(config.getServletContext()); + response = new HttpServletResponseSimulator(); + context = (ServletContextSimulator) config.getServletContext(); + isInitialized = true; + if (logger.isDebugEnabled()) + logger.debug("Exiting"); + } + + protected void tearDown() throws Exception { + ActionServlet servlet = getActionServlet(); + servlet.destroy(); + setActionServlet(servlet); + } + + /** + * Returns an HttpServletRequest object that can be used in + * this test. + */ + public HttpServletRequest getRequest() { + if (logger.isDebugEnabled()) + logger.debug("Entering"); + init(); + if (logger.isDebugEnabled()) + logger.debug("Exiting"); + return this.request; + } + + /** + * Clears all request parameters previously set. + */ + public void clearRequestParameters() { + if (logger.isTraceEnabled()) + logger.trace("Entering"); + this.request.getParameterMap().clear(); + + // also, clear out the redirect header if it's there. + response.removeHeader("Location"); + if (logger.isTraceEnabled()) + logger.trace("Exiting"); + } + + /** + * Returns an HttpServletResponse object that can be used in + * this test. + */ + public HttpServletResponse getResponse() { + if (logger.isDebugEnabled()) + logger.debug("Entering"); + init(); + if (logger.isDebugEnabled()) + logger.debug("Exiting"); + return this.response; + } + + /** + * Returns the mock HttpServletRequest object used in this test. This allows + * access to methods for setting up test preconditions that are otherwise + * unavailable through the normal Servlet API. + */ + public HttpServletRequestSimulator getMockRequest() { + if (logger.isTraceEnabled()) + logger.trace("Entering"); + init(); + if (logger.isTraceEnabled()) + logger.trace("Exiting"); + return this.request; + } + + /** + * Returns the mock HttpServletResponse object used in this test. This allows + * access to methods for setting up test preconditions that are otherwise + * unavailable through the normal Servlet API. + */ + public HttpServletResponseSimulator getMockResponse() { + if (logger.isTraceEnabled()) + logger.trace("Entering"); + init(); + if (logger.isTraceEnabled()) + logger.trace("Exiting"); + return this.response; + } + + /** + * Returns an HttpSession object that can be used in this + * test. + */ + public HttpSession getSession() { + if (logger.isDebugEnabled()) + logger.debug("Entering"); + init(); + if (logger.isDebugEnabled()) + logger.debug("Exiting"); + return this.request.getSession(true); + } + + /** + * Returns the ActionServlet controller used in this + * test. + * + */ + public ActionServlet getActionServlet() { + if (logger.isDebugEnabled()) + logger.debug("Entering"); + init(); + try { + if (!actionServletIsInitialized) { + if (logger.isDebugEnabled()) { + logger.debug("intializing actionServlet"); + } + this.actionServlet.init(config); + actionServletIsInitialized = true; + } + } catch (Exception e) { + logger.error("Error initializing action servlet",e); + if(e.getMessage().equals("java.lang.NullPointerException")){ + String message = "Error initializing action servlet: Unable to find /WEB-INF/web.xml. " + + "TestCase is running from " + System.getProperty("user.dir") + " directory. " + + "Context directory "; + if(this.context.getContextDirectory()==null){ + message += "has not been set. Try calling setContextDirectory() with a relative or absolute path"; + }else{ + message = message + "is " + this.context.getContextDirectory().getAbsolutePath(); + } + message = message + ". /WEB-INF/web.xml must be found under the context directory, " + + "the directory the test case is running from, or in the classpath."; + fail(message); + }else{ + throw new AssertionFailedError(e.getMessage()); + } + } + if (logger.isDebugEnabled()) + logger.debug("Exiting"); + return actionServlet; + } + + /** + * Sets the ActionServlet to be used in this test execution. This + * method should only be used if you plan to use a customized + * version different from that provided in the Struts distribution. + */ + public void setActionServlet(ActionServlet servlet) { + if (logger.isDebugEnabled()) + logger.debug("Entering - servlet = " + servlet); + init(); + if (servlet == null) + throw new AssertionFailedError("Cannot set ActionServlet to null"); + this.actionServlet = servlet; + if (logger.isDebugEnabled()) + logger.debug("Exiting"); + actionServletIsInitialized = false; + } + + /** + * Executes the Action instance to be tested. This method + * calls the ActionServlet.doPost() method to execute the + * Action instance to be tested, passing along any parameters + * set in the HttpServletRequest object. It stores any results + * for further validation. + * + * @exception AssertionFailedError if there are any execution + * errors while calling Action.execute() + * + */ + public void actionPerform() { + if (logger.isDebugEnabled()) + logger.debug("Entering"); + if(!this.requestPathSet){ + throw new IllegalStateException("You must call setRequestPathInfo() prior to calling actionPerform()."); + } + init(); + HttpServletRequest request = this.request; + HttpServletResponse response = this.response; + try { + this.getActionServlet().doPost(request,response); + }catch (NullPointerException npe) { + String message = "A NullPointerException was thrown. This may indicate an error in your ActionForm, or " + + "it may indicate that the Struts ActionServlet was unable to find struts config file. " + + "TestCase is running from " + System.getProperty("user.dir") + " directory. " + + "Context directory "; + if(this.context.getContextDirectory()==null){ + message += "has not been set. Try calling setContextDirectory() with a relative or absolute path"; + }else{ + message = message + "is " + this.context.getContextDirectory().getAbsolutePath(); + } + message = message + ". struts config file must be found under the context directory, " + + "the directory the test case is running from, or in the classpath."; + throw new ExceptionDuringTestError(message, npe); + }catch(Exception e){ + throw new ExceptionDuringTestError("An uncaught exception was thrown during actionExecute()", e); + } + if (logger.isDebugEnabled()) + logger.debug("Exiting"); + } + + /** + * Adds an HttpServletRequest parameter to be used in setting up the + * ActionForm instance to be used in this test. Each parameter added + * should correspond to an attribute in the ActionForm instance used + * by the Action instance being tested. + */ + public void addRequestParameter(String parameterName, String parameterValue) + { + if (logger.isDebugEnabled()) + logger.debug("Entering - parameterName = " + parameterName + ", parameterValue = " + parameterValue); + init(); + this.request.addParameter(parameterName,parameterValue); + if (logger.isDebugEnabled()) + logger.debug("Exiting"); + } + + /** + * Adds an HttpServletRequest parameter that is an array of String values + * to be used in setting up the ActionForm instance to be used in this test. + * Each parameter added should correspond to an attribute in the ActionForm + * instance used by the Action instance being tested. + */ + public void addRequestParameter(String parameterName, String[] parameterValues) + { + if (logger.isDebugEnabled()) + logger.debug("Entering - parameterName = " + parameterName + ", parameteValue = " + parameterValues); + init(); + this.request.addParameter(parameterName,parameterValues); + if (logger.isDebugEnabled()) + logger.debug("Exiting"); + } + + /** + * Sets the request path instructing the ActionServlet to used a + * particual ActionMapping. + * + * @param pathInfo the request path to be processed. This should + * correspond to a particular action mapping, as would normally + * appear in an HTML or JSP source file. + */ + public void setRequestPathInfo(String pathInfo) { + if (logger.isDebugEnabled()) + logger.debug("Entering - pathInfo = " + pathInfo); + init(); + this.setRequestPathInfo("",pathInfo); + if (logger.isDebugEnabled()) + logger.debug("Exiting"); + } + + /** + * Sets the request path instructing the ActionServlet to used a + * particual ActionMapping. Also sets the ServletPath property + * on the request. + * + * @param moduleName the name of the Struts sub-application with + * which this request is associated, or null if it is the default + * application. + * @param pathInfo the request path to be processed. This should + * correspond to a particular action mapping, as would normally + * appear in an HTML or JSP source file. If this request is part + * of a sub-application, the module name should not appear in the + * request path. + */ + public void setRequestPathInfo(String moduleName, String pathInfo) { + if (logger.isDebugEnabled()) + logger.debug("Entering - moduleName = " + moduleName + ", pathInfo = " + pathInfo); + init(); + this.actionPath = Common.stripActionPath(pathInfo); + if (moduleName != null) { + if (!moduleName.equals("")) { + if (!moduleName.startsWith("/")) + moduleName = "/" + moduleName; + if (!moduleName.endsWith("/")) + moduleName = moduleName + "/"; + } + if (logger.isDebugEnabled()) { + logger.debug("setting request attribute - name = " + Common.INCLUDE_SERVLET_PATH + ", value = " + moduleName); + } + this.request.setAttribute(Common.INCLUDE_SERVLET_PATH, moduleName); + } + this.request.setPathInfo(actionPath); + this.requestPathSet = true; + if (logger.isDebugEnabled()) + logger.debug("Exiting"); + } + + /** + * Sets an initialization parameter on the + * ActionServlet. Allows you to simulate an init parameter + * that would normally have been found in web.xml, + * but is not available while testing with mock objects. + * @param key the name of the initialization parameter + * @param value the value of the intialization parameter + */ + public void setInitParameter(String key, String value){ + if (logger.isDebugEnabled()) + logger.debug("Entering - key = " + key + ", value = " + value); + init(); + config.setInitParameter(key, value); + actionServletIsInitialized = false; + if (logger.isDebugEnabled()) + logger.debug("Exiting"); + } + + /** + * Sets the context directory to be used with the getRealPath() methods in + * the ServletContext and HttpServletRequest API. + * @param contextDirectory a File object representing the root context directory + * for this application. + */ + public void setContextDirectory(File contextDirectory) { + if (logger.isDebugEnabled()) + logger.debug("Entering - contextDirectory = " + contextDirectory); + init(); + context.setContextDirectory(contextDirectory); + actionServletIsInitialized = false; + if (logger.isDebugEnabled()) + logger.debug("Exiting"); + } + + /** + * Sets the location of the Struts configuration file for the default module. + * This method can take either an absolute path, or a relative path. If an + * absolute path is supplied, the configuration file will be loaded from the + * underlying filesystem; otherwise, the ServletContext loader will be used. + */ + public void setConfigFile(String pathname) { + if (logger.isDebugEnabled()) + logger.debug("Entering - pathName = " + pathname); + init(); + setConfigFile(null,pathname); + if (logger.isDebugEnabled()) + logger.debug("Exiting"); + } + + /** + * Sets the struts configuration file for a given sub-application. This method + * can take either an absolute path, or a relative path. If an absolute path + * is supplied, the configuration file will be loaded from the underlying + * filesystem; otherwise, the ServletContext loader will be used. + * + * @param moduleName the name of the sub-application, or null if this is the default application + * @param pathname the location of the configuration file for this sub-application + */ + public void setConfigFile(String moduleName, String pathname) { + if (logger.isDebugEnabled()) + logger.debug("Entering - moduleName = " + moduleName + ", pathname =" + pathname); + init(); + if (moduleName == null) + this.config.setInitParameter("config",pathname); + else + this.config.setInitParameter("config/" + moduleName,pathname); + actionServletIsInitialized = false; + if (logger.isDebugEnabled()) + logger.debug("Exiting"); + } + + /** + * Sets the location of the web.xml configuration file to be used + * to set up the servlet context and configuration for this test. + * This method supports both init-param and context-param tags, + * setting the ServletConfig and ServletContext appropriately. + * This method can take either an absolute path, or a relative path. If an + * absolute path is supplied, the configuration file will be loaded from the + * underlying filesystem; otherwise, the ServletContext loader will be used. + */ + public void setServletConfigFile(String pathname) { + if (logger.isDebugEnabled()) + logger.debug("Entering - pathname = " + pathname); + init(); + + // pull in the appropriate parts of the + // web.xml file -- first the init-parameters + Digester digester = new Digester(); + digester.push(this.config); + digester.setValidating(true); + digester.addCallMethod("web-app/servlet/init-param", "setInitParameter", 2); + digester.addCallParam("web-app/servlet/init-param/param-name", 0); + digester.addCallParam("web-app/servlet/init-param/param-value", 1); + try { + for (int i = 0; i < registrations.length; i += 2) { + URL url = context.getResource(registrations[i + 1]); + if (url != null) + digester.register(registrations[i], url.toString()); + } + InputStream input = context.getResourceAsStream(pathname); + if(input==null) + throw new AssertionFailedError("Invalid pathname: " + pathname); + digester.parse(input); + input.close(); + } catch (Exception e) { + throw new AssertionFailedError("Received an exception while loading web.xml - " + e.getClass() + " : " + e.getMessage()); + } + + // now the context parameters.. + digester = new Digester(); + digester.setValidating(true); + digester.push(this.context); + digester.addCallMethod("web-app/context-param", "setInitParameter", 2); + digester.addCallParam("web-app/context-param/param-name", 0); + digester.addCallParam("web-app/context-param/param-value", 1); + try { + for (int i = 0; i < registrations.length; i += 2) { + URL url = context.getResource(registrations[i + 1]); + if (url != null) + digester.register(registrations[i], url.toString()); + } + InputStream input = context.getResourceAsStream(pathname); + if(input==null) + throw new AssertionFailedError("Invalid pathname: " + pathname); + digester.parse(input); + input.close(); + } catch (Exception e) { + throw new AssertionFailedError("Received an exception while loading web.xml - " + e.getClass() + " : " + e.getMessage()); + } + actionServletIsInitialized = false; + if (logger.isDebugEnabled()) + logger.debug("Exiting"); + } + + /** + * Returns the forward sent to RequestDispatcher. + */ + protected String getActualForward() { + if (logger.isDebugEnabled()) + logger.debug("Entering"); + if (response.containsHeader("Location")) { + return Common.stripJSessionID(response.getHeader("Location")); + } else + try { + String strippedForward = request.getContextPath() + Common.stripJSessionID(((ServletContextSimulator) config.getServletContext()).getRequestDispatcherSimulator().getForward()); + if (logger.isDebugEnabled()) { + logger.debug("stripped forward and added context path - " + strippedForward); + } + if (logger.isDebugEnabled()) + logger.debug("Exiting"); + return strippedForward; + } catch (NullPointerException npe) { + if (logger.isDebugEnabled()) { + logger.debug("caught NullPointerException - returning null",npe); + } + return null; + } + } + + /** + * Verifies if the ActionServlet controller used this forward. + * + * @param forwardName the logical name of a forward, as defined + * in the Struts configuration file. This can either refer to a + * global forward, or one local to the ActionMapping. + * + * @exception AssertionFailedError if the ActionServlet controller + * used a different forward than forwardName after + * executing an Action object. + */ + public void verifyForward(String forwardName) throws AssertionFailedError { + if (logger.isDebugEnabled()) + logger.debug("Entering - forwardName = " + forwardName); + init(); + Common.verifyForwardPath(actionPath,forwardName,getActualForward(),false,request,config.getServletContext(),config); + if (logger.isDebugEnabled()) + logger.debug("Exiting"); + } + + /** + * Verifies if the ActionServlet controller used this actual path + * as a forward. + * + * @param forwardPath an absolute pathname to which the request + * is to be forwarded. + * + * @exception AssertionFailedError if the ActionServlet controller + * used a different forward path than forwardPath after + * executing an Action object. + */ + public void verifyForwardPath(String forwardPath) throws AssertionFailedError { + if (logger.isDebugEnabled()) + logger.debug("Entering - forwardPath = " + forwardPath); + init(); + String actualForward = getActualForward(); + if ((actualForward == null) && (forwardPath == null)) { + // actions can send null forwards, which is fine. + return; + } + + forwardPath = request.getContextPath() + forwardPath; + + if (actualForward == null) { + if (logger.isDebugEnabled()) { + logger.debug("actualForward is null - this usually means it is not mapped properly."); + } + throw new AssertionFailedError("Was expecting '" + forwardPath + "' but it appears the Action has tried to return an ActionForward that is not mapped correctly."); + } + if (logger.isDebugEnabled()) { + logger.debug("expected forward = '" + forwardPath + "' - actual forward = '" + actualForward + "'"); + } + if (!(actualForward.equals(forwardPath))) + throw new AssertionFailedError("was expecting '" + forwardPath + "' but received '" + actualForward + "'"); + if (logger.isDebugEnabled()) + logger.debug("Exiting"); + } + + /** + * Verifies if the ActionServlet controller forwarded to the defined + * input path. + * + * @exception AssertionFailedError if the ActionServlet controller + * used a different forward than the defined input path after + * executing an Action object. + */ + public void verifyInputForward() { + if (logger.isDebugEnabled()) + logger.debug("Entering"); + init(); + Common.verifyForwardPath(actionPath,null,getActualForward(),true,request,config.getServletContext(),config); + if (logger.isDebugEnabled()) + logger.debug("Exiting"); + } + + /** + * Verifies that the ActionServlet controller used this forward and Tiles definition. + * + * @param forwardName the logical name of a forward, as defined + * in the Struts configuration file. This can either refer to a + * global forward, or one local to the ActionMapping. + * + * @param definitionName the name of a Tiles definition, as defined + * in the Tiles configuration file. + * + * @exception AssertionFailedError if the ActionServlet controller + * used a different forward or tiles definition than those given after + * executing an Action object. + */ + public void verifyTilesForward(String forwardName, String definitionName) { + if (logger.isTraceEnabled()) + logger.trace("Entering - forwardName=" + forwardName + ", definitionName=" + definitionName); + init(); + Common.verifyTilesForward(actionPath,forwardName,definitionName,false,request,config.getServletContext(),config); + if (logger.isTraceEnabled()) + logger.trace("Exiting"); + } + + /** + * Verifies that the ActionServlet controller forwarded to the defined + * input Tiles definition. + * + * @param definitionName the name of a Tiles definition, as defined + * in the Tiles configuration file. + * + * @exception AssertionFailedError if the ActionServlet controller + * used a different forward than the defined input path after + * executing an Action object. + */ + public void verifyInputTilesForward(String definitionName) { + if (logger.isTraceEnabled()) + logger.trace("Entering - definitionName=" + definitionName); + init(); + Common.verifyTilesForward(actionPath,null,definitionName,true,request,config.getServletContext(),config); + if (logger.isTraceEnabled()) + logger.trace("Exiting"); + } + + /** + * Verifies if the ActionServlet controller sent these error messages. + * There must be an exact match between the provided error messages, and + * those sent by the controller, in both name and number. + * + * @param errorNames a String array containing the error message keys + * to be verified, as defined in the application resource properties + * file. + * + * @exception AssertionFailedError if the ActionServlet controller + * sent different error messages than those in errorNames + * after executing an Action object. + */ + + public void verifyActionErrors(String[] errorNames) { + if (logger.isDebugEnabled()) + logger.debug("errorNames = " + errorNames); + init(); + Common.verifyActionMessages(request,errorNames,Globals.ERROR_KEY,"error"); + if (logger.isDebugEnabled()) + logger.debug("Exiting"); + } + + + /** + * Verifies that the ActionServlet controller sent no error messages upon + * executing an Action object. + * + * @exception AssertionFailedError if the ActionServlet controller + * sent any error messages after excecuting and Action object. + */ + public void verifyNoActionErrors() { + if (logger.isDebugEnabled()) + logger.debug("Entering"); + init(); + Common.verifyNoActionMessages(request,Globals.ERROR_KEY,"error"); + if (logger.isDebugEnabled()) + logger.debug("Exiting"); + } + + /** + * Verifies if the ActionServlet controller sent these action messages. + * There must be an exact match between the provided action messages, and + * those sent by the controller, in both name and number. + * + * @param messageNames a String array containing the action message keys + * to be verified, as defined in the application resource properties + * file. + * + * @exception AssertionFailedError if the ActionServlet controller + * sent different action messages than those in messageNames + * after executing an Action object. + */ + public void verifyActionMessages(String[] messageNames) { + if (logger.isDebugEnabled()) + logger.debug("Entering - messageNames = " + messageNames); + init(); + Common.verifyActionMessages(request,messageNames,Globals.MESSAGE_KEY,"action"); + if (logger.isDebugEnabled()) + logger.debug("Exiting"); + } + + /** + * Verifies that the ActionServlet controller sent no action messages upon + * executing an Action object. + * + * @exception AssertionFailedError if the ActionServlet controller + * sent any action messages after excecuting and Action object. + */ + public void verifyNoActionMessages() { + if (logger.isDebugEnabled()) + logger.debug("Entering"); + init(); + Common.verifyNoActionMessages(request,Globals.MESSAGE_KEY,"action"); + if (logger.isDebugEnabled()) + logger.debug("Exiting"); + } + + /** + * Returns the ActionForm instance stored in either the request or session. Note + * that no form will be returned if the Action being tested cleans up the form + * instance. + * + * @ return the ActionForm instance used in this test, or null if it does not exist. + */ + public ActionForm getActionForm() { + if (logger.isDebugEnabled()) + logger.debug("Entering"); + init(); + if (logger.isDebugEnabled()) + logger.debug("Exiting"); + return Common.getActionForm(actionPath,request,context); + } + + /** + * Sets an ActionForm instance to be used in this test. The given ActionForm instance + * will be stored in the scope specified in the Struts configuration file (ie: request + * or session). Note that while this ActionForm instance is passed to the test, Struts + * will still control how it is used. In particular, it will call the ActionForm.reset() + * method, so if you override this method in your ActionForm subclass, you could potentially + * reset attributes in the form passed through this method. + * + * @param form the ActionForm instance to be used in this test. + */ + public void setActionForm(ActionForm form) { + if (logger.isDebugEnabled()) + logger.debug("Entering - form = " + form); + init(); + // make sure action servlet is intialized + getActionServlet(); + Common.setActionForm(form,request,actionPath,context); + if (logger.isDebugEnabled()) + logger.debug("Exiting"); + } + + + + +} + Index: 3rdParty_sources/strutstest/servletunit/struts/2_2/StrutsRequestWrapper.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/strutstest/servletunit/struts/2_2/Attic/StrutsRequestWrapper.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/strutstest/servletunit/struts/2_2/StrutsRequestWrapper.java 17 Aug 2012 15:17:19 -0000 1.1 @@ -0,0 +1,111 @@ +// StrutsTestCase - a JUnit extension for testing Struts actions +// within the context of the ActionServlet. +// Copyright (C) 2002 Deryl Seale +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the Apache Software License as +// published by the Apache Software Foundation; either version 1.1 +// of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// Apache Software Foundation Licens for more details. +// +// You may view the full text here: http://www.apache.org/LICENSE.txt + +package servletunit.struts; + +import org.apache.cactus.ServletURL; +import org.apache.cactus.server.HttpServletRequestWrapper; + +import java.util.*; + +/** + * A wrapper for the HttpServletRequest class. This is used in + * CactusStrutsTestCase so that we can add our own request parameters + * outside of the beginXXX and endXXX methods. This allows us to + * to use the ActionServlet as a black box, rather than mimic its + * behavior as was previously the case. + */ +public class StrutsRequestWrapper extends HttpServletRequestWrapper { + + private String pathInfo; + private String servletPath; + private Map parameters; + + public StrutsRequestWrapper(HttpServletRequestWrapper request) { + super(request,new ServletURL(request.getServerName(),request.getContextPath(),request.getServletPath(),request.getPathInfo(),request.getQueryString())); + parameters = new HashMap(); + } + + public void setPathInfo(String pathInfo) { + this.pathInfo = pathInfo; + } + + public String getPathInfo() { + if (this.pathInfo == null) + return super.getPathInfo(); + else + return this.pathInfo; + } + + public void setServletPath(String servletPath) { + this.servletPath = servletPath; + } + + public String getServletPath() { + if (this.servletPath == null) + return super.getServletPath(); + else + return this.servletPath; + } + + + public String getParameter(String name) { + String[] result = getParameterValues(name); + if ((result != null) && (result.length > 0)) { + return result[0]; + } else + return null; + } + + public String[] getParameterValues(String name) { + Object result = super.getParameterValues(name); + if ((result == null) && (parameters.containsKey(name))) { + result = parameters.get(name); + if (!(result instanceof String[])) { + String[] resultArray = { result.toString() }; + result = resultArray; + } + } + return (String[]) result; + } + + public Enumeration getParameterNames() { + Enumeration superNames = super.getParameterNames(); + List nameList = new ArrayList(parameters.keySet()); + while (superNames.hasMoreElements()) { + nameList.add(superNames.nextElement()); + } + return Collections.enumeration(nameList); + } + + public void addParameter(String name, String value) { + if ((super.getParameter(name) == null) && (name != null) && (value != null)) + parameters.put(name,value); + } + + public void addParameter(String name, String[] values) { + if ((super.getParameter(name) == null) && (name != null) && (values != null)) + parameters.put(name,values); + } + + public void clearRequestParameters() { + this.parameters.clear(); +// super.request.getParameterMap().clear(); + } + +} + + Index: 3rdParty_sources/strutstest/servletunit/struts/2_2/StrutsResponseWrapper.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/strutstest/servletunit/struts/2_2/Attic/StrutsResponseWrapper.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/strutstest/servletunit/struts/2_2/StrutsResponseWrapper.java 17 Aug 2012 15:17:19 -0000 1.1 @@ -0,0 +1,198 @@ +// StrutsTestCase - a JUnit extension for testing Struts actions +// within the context of the ActionServlet. +// Copyright (C) 2002 Deryl Seale +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the Apache Software License as +// published by the Apache Software Foundation; either version 1.1 +// of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// Apache Software Foundation Licens for more details. +// +// You may view the full text here: http://www.apache.org/LICENSE.txt + +package servletunit.struts; + +import javax.servlet.ServletOutputStream; +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.Locale; + +/** + * A wrapper for the HttpServletResponse class. This is used in + * CactusStrutsTestCase so that we can retrieve the redirect URL + * set by the ActionServlet in processing an action. This allows + * us to use the ActionServlet as a black box, rather than mimic + * its behavior as was previously the case. + */ +public class StrutsResponseWrapper implements HttpServletResponse +{ + + private HttpServletResponse response; + private String redirectLocation; + + public StrutsResponseWrapper(HttpServletResponse response) { + this.response = response; + } + + public void addCookie(Cookie cookie) + { + this.response.addCookie(cookie); + } + + public void addDateHeader(String name, long date) + { + this.response.addDateHeader(name,date); + } + + public void addHeader(String name, String value) + { + this.response.addHeader(name,value); + } + + public void addIntHeader(String name, int value) + { + this.response.addIntHeader(name,value); + } + + public boolean containsHeader(String name) + { + return this.response.containsHeader(name); + } + + public String encodeRedirectUrl(String url) + { + return this.response.encodeRedirectUrl(url); + } + + public String encodeRedirectURL(String url) + { + return this.response.encodeRedirectURL(url); + } + + public String encodeUrl(String url) + { + return this.response.encodeUrl(url); + } + + public String encodeURL(String url) + { + return this.response.encodeURL(url); + } + + public void flushBuffer() throws IOException + { + this.response.flushBuffer(); + } + + public int getBufferSize() + { + return this.response.getBufferSize(); + } + + public String getCharacterEncoding() + { + return this.response.getCharacterEncoding(); + } + + public Locale getLocale() + { + return this.response.getLocale(); + } + + public ServletOutputStream getOutputStream() throws IOException + { + return this.response.getOutputStream(); + } + + public PrintWriter getWriter() throws IOException + { + return this.response.getWriter(); + } + + public boolean isCommitted() + { + return this.response.isCommitted(); + } + + public void reset() + { + this.response.reset(); + } + + public void resetBuffer() + { + } + + public void sendError(int sc) throws IOException + { + this.response.sendError(sc); + } + + public void sendError(int sc, String msg) throws IOException + { + this.response.sendError(sc,msg); + } + + public void sendRedirect(String location) throws IOException + { + this.redirectLocation = location; + this.response.sendRedirect(location); + } + + public void setBufferSize(int size) + { + this.response.setBufferSize(size); + } + + public void setContentLength(int len) + { + this.response.setContentLength(len); + } + + public void setContentType(String type) + { + this.response.setContentType(type); + } + + public void setDateHeader(String name, long date) + { + this.response.setDateHeader(name,date); + } + + public void setHeader(String name, String value) + { + this.response.setHeader(name,value); + } + + public void setIntHeader(String name, int value) + { + this.response.setIntHeader(name,value); + } + + public void setStatus(int sc) + { + this.response.setStatus(sc); + } + + public void setStatus(int sc, String sm) + { + this.response.setStatus(sc,sm); + } + + public void setLocale(Locale loc) + { + this.response.setLocale(loc); + } + + public String getRedirectLocation() { + return this.redirectLocation; + } + +} + Index: 3rdParty_sources/strutstest/servletunit/struts/2_4/StrutsResponseWrapper.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/strutstest/servletunit/struts/2_4/Attic/StrutsResponseWrapper.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/strutstest/servletunit/struts/2_4/StrutsResponseWrapper.java 17 Aug 2012 15:17:21 -0000 1.1 @@ -0,0 +1,207 @@ +// StrutsTestCase - a JUnit extension for testing Struts actions +// within the context of the ActionServlet. +// Copyright (C) 2002 Deryl Seale +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the Apache Software License as +// published by the Apache Software Foundation; either version 1.1 +// of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// Apache Software Foundation Licens for more details. +// +// You may view the full text here: http://www.apache.org/LICENSE.txt + +package servletunit.struts; + +import javax.servlet.ServletOutputStream; +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.Locale; + +/** + * A wrapper for the HttpServletResponse class. This is used in + * CactusStrutsTestCase so that we can retrieve the redirect URL + * set by the ActionServlet in processing an action. This allows + * us to use the ActionServlet as a black box, rather than mimic + * its behavior as was previously the case. + */ +public class StrutsResponseWrapper implements HttpServletResponse +{ + + private HttpServletResponse response; + private String redirectLocation; + + public StrutsResponseWrapper(HttpServletResponse response) { + this.response = response; + } + + public void addCookie(Cookie cookie) + { + this.response.addCookie(cookie); + } + + public void addDateHeader(String name, long date) + { + this.response.addDateHeader(name,date); + } + + public void addHeader(String name, String value) + { + this.response.addHeader(name,value); + } + + public void addIntHeader(String name, int value) + { + this.response.addIntHeader(name,value); + } + + public boolean containsHeader(String name) + { + return this.response.containsHeader(name); + } + + public String encodeRedirectUrl(String url) + { + return this.response.encodeRedirectUrl(url); + } + + public String encodeRedirectURL(String url) + { + return this.response.encodeRedirectURL(url); + } + + public String encodeUrl(String url) + { + return this.response.encodeUrl(url); + } + + public String encodeURL(String url) + { + return this.response.encodeURL(url); + } + + public void flushBuffer() throws IOException + { + this.response.flushBuffer(); + } + + public int getBufferSize() + { + return this.response.getBufferSize(); + } + + public String getCharacterEncoding() + { + return this.response.getCharacterEncoding(); + } + + public String getContentType() { + return this.response.getContentType(); + } + + public Locale getLocale() + { + return this.response.getLocale(); + } + + public ServletOutputStream getOutputStream() throws IOException + { + return this.response.getOutputStream(); + } + + public PrintWriter getWriter() throws IOException + { + return this.response.getWriter(); + } + + public void setCharacterEncoding(String s) { + this.setCharacterEncoding(s); + } + + public boolean isCommitted() + { + return this.response.isCommitted(); + } + + public void reset() + { + this.response.reset(); + } + + public void resetBuffer() + { + this.response.resetBuffer(); + } + + public void sendError(int sc) throws IOException + { + this.response.sendError(sc); + } + + public void sendError(int sc, String msg) throws IOException + { + this.response.sendError(sc,msg); + } + + public void sendRedirect(String location) throws IOException + { + this.redirectLocation = location; + this.response.sendRedirect(location); + } + + public void setBufferSize(int size) + { + this.response.setBufferSize(size); + } + + public void setContentLength(int len) + { + this.response.setContentLength(len); + } + + public void setContentType(String type) + { + this.response.setContentType(type); + } + + public void setDateHeader(String name, long date) + { + this.response.setDateHeader(name,date); + } + + public void setHeader(String name, String value) + { + this.response.setHeader(name,value); + } + + public void setIntHeader(String name, int value) + { + this.response.setIntHeader(name,value); + } + + public void setStatus(int sc) + { + this.response.setStatus(sc); + } + + public void setStatus(int sc, String sm) + { + this.response.setStatus(sc,sm); + } + + public void setLocale(Locale loc) + { + this.response.setLocale(loc); + } + + public String getRedirectLocation() { + return this.redirectLocation; + } + +} + Index: 3rdParty_sources/strutstest/servletunit/struts/tests/ComplexForm.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/strutstest/servletunit/struts/tests/Attic/ComplexForm.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/strutstest/servletunit/struts/tests/ComplexForm.java 17 Aug 2012 15:17:05 -0000 1.1 @@ -0,0 +1,58 @@ +/* + * User: dxseale + * Date: Nov 7, 2002 + */ +package servletunit.struts.tests; + +import org.apache.struts.action.ActionForm; +import org.apache.struts.action.ActionMapping; + +import javax.servlet.http.HttpServletRequest; + +public class ComplexForm extends ActionForm { + + private Object complexObject; + private String username; + private String password; + + public String getUsername() { + if (username != null) + return username; + else + return ""; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getPassword() { + if (password != null) + return password; + else + return ""; + } + + public void setPassword(String password) { + this.password = password; + } + + public Object getComplexObject() { + return complexObject; + } + + public void setComplexObject(Object complexObject) { + this.complexObject = complexObject; + } + + public void reset(ActionMapping mapping, HttpServletRequest request) { + String testFlag = request.getParameter("test.reset"); + if ((testFlag != null) && (testFlag.equals("true"))) { + this.setComplexObject(null); + this.setPassword(null); + this.setUsername(null); + } + } + + +} Index: 3rdParty_sources/strutstest/servletunit/struts/tests/ComplexFormAction.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/strutstest/servletunit/struts/tests/Attic/ComplexFormAction.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/strutstest/servletunit/struts/tests/ComplexFormAction.java 17 Aug 2012 15:17:04 -0000 1.1 @@ -0,0 +1,55 @@ +// StrutsTestCase - a JUnit extension for testing Struts actions +// within the context of the ActionServlet. +// Copyright (C) 2002 Deryl Seale +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the Apache Software License as +// published by the Apache Software Foundation; either version 1.1 +// of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// Apache Software Foundation Licens for more details. +// +// You may view the full text here: http://www.apache.org/LICENSE.txt + +package servletunit.struts.tests; + +import org.apache.struts.action.*; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +public class ComplexFormAction extends Action { + + /** + * This class is reserved for quickly testing out other + * user's actions, to help in debugging their problems. + * It is deliberately checked in empty, as it is a place- + * holder. + */ + public ActionForward execute(ActionMapping mapping, + ActionForm form, + HttpServletRequest request, + HttpServletResponse response) { + + ComplexForm complexForm = (ComplexForm) form; + + String username = complexForm.getUsername(); + String password = complexForm.getPassword(); + + ActionErrors errors = new ActionErrors(); + + if ((!username.equals("deryl")) || (!password.equals("radar")) || (complexForm.getComplexObject() == null)) + errors.add("password",new ActionMessage("error.password.mismatch")); + + if (!errors.isEmpty()) { + saveErrors(request,errors); + return mapping.findForward("login"); + } + + return mapping.findForward("success"); + } + +} Index: 3rdParty_sources/strutstest/servletunit/struts/tests/CustomMappingAction.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/strutstest/servletunit/struts/tests/Attic/CustomMappingAction.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/strutstest/servletunit/struts/tests/CustomMappingAction.java 17 Aug 2012 15:17:05 -0000 1.1 @@ -0,0 +1,18 @@ +package servletunit.struts.tests; + +import org.apache.struts.action.*; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +public class CustomMappingAction extends Action { + + public ActionForward execute(ActionMapping actionMapping, ActionForm actionForm, HttpServletRequest servletRequest, HttpServletResponse servletResponse) throws Exception { + if (actionMapping instanceof RequestActionMapping) { + return actionMapping.findForward("success"); + } + else + return actionMapping.findForward("failure"); + } + +} + Index: 3rdParty_sources/strutstest/servletunit/struts/tests/DynamicAction.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/strutstest/servletunit/struts/tests/Attic/DynamicAction.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/strutstest/servletunit/struts/tests/DynamicAction.java 17 Aug 2012 15:17:05 -0000 1.1 @@ -0,0 +1,63 @@ +// StrutsTestCase - a JUnit extension for testing Struts actions +// within the context of the ActionServlet. +// Copyright (C) 2002 Deryl Seale +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the Apache Software License as +// published by the Apache Software Foundation; either version 1.1 +// of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// Apache Software Foundation Licens for more details. +// +// You may view the full text here: http://www.apache.org/LICENSE.txt + +package servletunit.struts.tests; + +import org.apache.struts.action.*; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; + +public class DynamicAction extends Action { + + public ActionForward execute(ActionMapping mapping, + ActionForm form, + HttpServletRequest request, + HttpServletResponse response) { + + DynaActionForm dynaForm = (DynaActionForm) form; + String username = (String) dynaForm.get("username"); + String password = (String) dynaForm.get("password"); + + ActionErrors errors = new ActionErrors(); + + if ((!username.equals("deryl")) || (!password.equals("radar"))) + errors.add("password",new ActionMessage("error.password.mismatch")); + + if (!errors.isEmpty()) { + saveErrors(request,errors); + return mapping.findForward("login"); + } + + HttpSession session = request.getSession(); + session.setAttribute("authentication", username); + + // Remove the obsolete form bean + if (mapping.getAttribute() != null) { + if ("request".equals(mapping.getScope())) + request.removeAttribute(mapping.getAttribute()); + else + session.removeAttribute(mapping.getAttribute()); + } + + // Forward control to the specified success URI + return mapping.findForward("success"); + + } + +} + Index: 3rdParty_sources/strutstest/servletunit/struts/tests/InitParameterAction.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/strutstest/servletunit/struts/tests/Attic/InitParameterAction.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/strutstest/servletunit/struts/tests/InitParameterAction.java 17 Aug 2012 15:17:05 -0000 1.1 @@ -0,0 +1,45 @@ +// StrutsTestCase - a JUnit extension for testing Struts actions +// within the context of the ActionServlet. +// Copyright (C) 2002 Deryl Seale +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the Apache Software License as +// published by the Apache Software Foundation; either version 1.1 +// of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// Apache Software Foundation Licens for more details. +// +// You may view the full text here: http://www.apache.org/LICENSE.txt + +package servletunit.struts.tests; + +import org.apache.struts.action.*; + +import javax.servlet.ServletContext; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +public class InitParameterAction extends Action { + + public ActionForward execute(ActionMapping mapping, + ActionForm form, + HttpServletRequest request, + HttpServletResponse response) { + + ActionErrors errors = new ActionErrors(); + + ServletContext context = getServlet().getServletContext(); + if (context != null) { + if (context.getInitParameter("username") == null) + errors.add("",new ActionMessage("error.init.param")); + } else + errors.add("",new ActionMessage("error.no.context")); + if (!errors.isEmpty()) + saveErrors(request,errors); + return mapping.findForward("login"); + } + +} Index: 3rdParty_sources/strutstest/servletunit/struts/tests/MessageAction.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/strutstest/servletunit/struts/tests/Attic/MessageAction.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/strutstest/servletunit/struts/tests/MessageAction.java 17 Aug 2012 15:17:06 -0000 1.1 @@ -0,0 +1,39 @@ +// StrutsTestCase - a JUnit extension for testing Struts actions +// within the context of the ActionServlet. +// Copyright (C) 2002 Deryl Seale +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the Apache Software License as +// published by the Apache Software Foundation; either version 1.1 +// of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// Apache Software Foundation Licens for more details. +// +// You may view the full text here: http://www.apache.org/LICENSE.txt + +package servletunit.struts.tests; + +import org.apache.struts.action.*; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +public class MessageAction extends Action { + + + + public ActionForward execute(ActionMapping mapping, + ActionForm form, + HttpServletRequest request, + HttpServletResponse response) { + ActionMessages messages = new ActionMessages(); + messages.add("test",new ActionMessage("test.message")); + saveMessages(request,messages); + return mapping.findForward("success"); + } + +} + Index: 3rdParty_sources/strutstest/servletunit/struts/tests/MessageResourceAction.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/strutstest/servletunit/struts/tests/Attic/MessageResourceAction.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/strutstest/servletunit/struts/tests/MessageResourceAction.java 17 Aug 2012 15:17:05 -0000 1.1 @@ -0,0 +1,57 @@ +// StrutsTestCase - a JUnit extension for testing Struts actions +// within the context of the ActionServlet. +// Copyright (C) 2002 Deryl Seale +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the Apache Software License as +// published by the Apache Software Foundation; either version 1.1 +// of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// Apache Software Foundation Licens for more details. +// +// You may view the full text here: http://www.apache.org/LICENSE.txt + +package servletunit.struts.tests; + +import org.apache.struts.action.Action; +import org.apache.struts.action.ActionForm; +import org.apache.struts.action.ActionForward; +import org.apache.struts.action.ActionMapping; +import org.apache.struts.util.MessageResources; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +public class MessageResourceAction extends Action { + + + + public ActionForward execute(ActionMapping mapping, + ActionForm form, + HttpServletRequest request, + HttpServletResponse response) { + + MessageResources resources = getResources(request); + if (resources == null) { + return mapping.findForward("failure"); + } else { + String message = resources.getMessage("button.save"); + if ((message != null) && (message.equals("Save"))) + return mapping.findForward("success"); + else { + return mapping.findForward("failure"); + } + } + } + +} + + + + + + + Index: 3rdParty_sources/strutstest/servletunit/struts/tests/MyDispatchAction.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/strutstest/servletunit/struts/tests/Attic/MyDispatchAction.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/strutstest/servletunit/struts/tests/MyDispatchAction.java 17 Aug 2012 15:17:05 -0000 1.1 @@ -0,0 +1,46 @@ +/* + * User: dxseale + * Date: Nov 8, 2002 + */ +package servletunit.struts.tests; + +import org.apache.struts.actions.DispatchAction; +import org.apache.struts.action.ActionForward; +import org.apache.struts.action.ActionMapping; +import org.apache.struts.action.ActionForm; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.ServletException; +import java.io.IOException; + +public class MyDispatchAction extends DispatchAction { + + public ActionForward actionOne(ActionMapping mapping, + ActionForm form, + HttpServletRequest request, + HttpServletResponse response) + throws IOException, ServletException + { + return mapping.findForward("action1"); + } + + public ActionForward actionTwo(ActionMapping mapping, + ActionForm form, + HttpServletRequest request, + HttpServletResponse response) + throws IOException, ServletException + { + return mapping.findForward("action2"); + } + + public ActionForward actionThree(ActionMapping mapping, + ActionForm form, + HttpServletRequest request, + HttpServletResponse response) + throws IOException, ServletException + { + return new ActionForward(mapping.getInput()); + } + +} Index: 3rdParty_sources/strutstest/servletunit/struts/tests/NullAction.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/strutstest/servletunit/struts/tests/Attic/NullAction.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/strutstest/servletunit/struts/tests/NullAction.java 17 Aug 2012 15:17:05 -0000 1.1 @@ -0,0 +1,24 @@ +package servletunit.struts.tests; + +import org.apache.struts.action.Action; +import org.apache.struts.action.ActionForward; +import org.apache.struts.action.ActionMapping; +import org.apache.struts.action.ActionForm; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +/** + * Created by IntelliJ IDEA. + * User: deryl + * Date: Apr 13, 2003 + * Time: 12:05:58 PM + * To change this template use Options | File Templates. + */ +public class NullAction extends Action { + + public ActionForward execute(ActionMapping actionMapping, ActionForm actionForm, HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception { + return null; + } + +} Index: 3rdParty_sources/strutstest/servletunit/struts/tests/NullPointerAction.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/strutstest/servletunit/struts/tests/Attic/NullPointerAction.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/strutstest/servletunit/struts/tests/NullPointerAction.java 17 Aug 2012 15:17:06 -0000 1.1 @@ -0,0 +1,46 @@ +// StrutsTestCase - a JUnit extension for testing Struts actions +// within the context of the ActionServlet. +// Copyright (C) 2002 Deryl Seale +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the Apache Software License as +// published by the Apache Software Foundation; either version 1.1 +// of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// Apache Software Foundation Licens for more details. +// +// You may view the full text here: http://www.apache.org/LICENSE.txt +package servletunit.struts.tests; + +import org.apache.struts.action.*; +import javax.servlet.http.*; + +/** + * An action that always throws a NullPointerException for use in testing + * + * @author Sean Pritchard + * @created November 20, 2003 + */ +public class NullPointerAction extends Action { + + /** + * Constructor for the NullPointerAction object + */ + public NullPointerAction() { } + + + /** + * Always throws a NullPointerException + * + */ + public ActionForward execute(ActionMapping mapping, + ActionForm form, + HttpServletRequest request, + HttpServletResponse response) + throws Exception { + throw new NullPointerException("simulates null pointer from misbehaving action"); + } +} Index: 3rdParty_sources/strutstest/servletunit/struts/tests/NullPointerForm.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/strutstest/servletunit/struts/tests/Attic/NullPointerForm.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/strutstest/servletunit/struts/tests/NullPointerForm.java 17 Aug 2012 15:17:04 -0000 1.1 @@ -0,0 +1,20 @@ +package servletunit.struts.tests; + +import org.apache.struts.action.*; +import javax.servlet.http.*; + +/** + * An Action Form that always throws a NullPointerAction during validation. + * Used in unit testing + * @author Sean Pritchard + * @version 1.0 + */ +public class NullPointerForm extends ActionForm { + + public NullPointerForm() { + } + + public ActionErrors validate(ActionMapping mapping, HttpServletRequest request){ + throw new NullPointerException("NullPointer during validation"); + } +} \ No newline at end of file Index: 3rdParty_sources/strutstest/servletunit/struts/tests/RedirectAction.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/strutstest/servletunit/struts/tests/Attic/RedirectAction.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/strutstest/servletunit/struts/tests/RedirectAction.java 17 Aug 2012 15:17:05 -0000 1.1 @@ -0,0 +1,37 @@ +// StrutsTestCase - a JUnit extension for testing Struts actions +// within the context of the ActionServlet. +// Copyright (C) 2002 Deryl Seale +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the Apache Software License as +// published by the Apache Software Foundation; either version 1.1 +// of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// Apache Software Foundation Licens for more details. +// +// You may view the full text here: http://www.apache.org/LICENSE.txt + +package servletunit.struts.tests; + +import org.apache.struts.action.Action; +import org.apache.struts.action.ActionForm; +import org.apache.struts.action.ActionForward; +import org.apache.struts.action.ActionMapping; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +public class RedirectAction extends Action { + + public ActionForward execute(ActionMapping mapping, + ActionForm form, + HttpServletRequest request, + HttpServletResponse response) { + + return mapping.findForward("redirect"); + } + +} Index: 3rdParty_sources/strutstest/servletunit/struts/tests/TestAbsolutePath.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/strutstest/servletunit/struts/tests/Attic/TestAbsolutePath.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/strutstest/servletunit/struts/tests/TestAbsolutePath.java 17 Aug 2012 15:17:05 -0000 1.1 @@ -0,0 +1,69 @@ +// StrutsTestCase - a JUnit extension for testing Struts actions +// within the context of the ActionServlet. +// Copyright (C) 2002 Deryl Seale +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the Apache Software License as +// published by the Apache Software Foundation; either version 1.1 +// of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// Apache Software Foundation Licens for more details. +// +// You may view the full text here: http://www.apache.org/LICENSE.txt + +package servletunit.struts.tests; + +import servletunit.struts.MockStrutsTestCase; +import servletunit.ServletContextSimulator; + +import java.io.File; + +public class TestAbsolutePath extends MockStrutsTestCase { + + String rootPath; + + public TestAbsolutePath(String testName) { + super(testName); + } + + public void setUp() throws Exception { + super.setUp(); + rootPath = System.getProperty("basedir"); + setServletConfigFile(rootPath + "/src/examples/WEB-INF/web.xml"); + } + + public void testSuccessfulLogin() { + setConfigFile(rootPath + "/src/examples/WEB-INF/struts-config.xml"); + addRequestParameter("username","deryl"); + addRequestParameter("password","radar"); + setRequestPathInfo("/login"); + actionPerform(); + verifyForward("success"); + verifyForwardPath("/main/success.jsp"); + assertEquals("deryl",getSession().getAttribute("authentication")); + verifyNoActionErrors(); + } + + public void testContextDirectory() { + this.setContextDirectory(new File(rootPath + "/src/examples")); + setConfigFile("/WEB-INF/struts-config.xml"); + addRequestParameter("username","deryl"); + addRequestParameter("password","radar"); + setRequestPathInfo("/login"); + actionPerform(); + verifyForward("success"); + verifyForwardPath("/main/success.jsp"); + assertEquals("deryl",getSession().getAttribute("authentication")); + verifyNoActionErrors(); + } + + public static void main(String[] args) { + junit.textui.TestRunner.run(TestAbsolutePath.class); + } + + +} + Index: 3rdParty_sources/strutstest/servletunit/struts/tests/TestBadModuleName.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/strutstest/servletunit/struts/tests/Attic/TestBadModuleName.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/strutstest/servletunit/struts/tests/TestBadModuleName.java 17 Aug 2012 15:17:05 -0000 1.1 @@ -0,0 +1,39 @@ +package servletunit.struts.tests; + +import servletunit.struts.MockStrutsTestCase; +import junit.framework.AssertionFailedError; + +/** + * Created by IntelliJ IDEA. + * User: deryl + * Date: Apr 28, 2003 + * Time: 9:26:32 AM + * To change this template use Options | File Templates. + */ +public class TestBadModuleName extends MockStrutsTestCase { + + public TestBadModuleName(String testName) { + super(testName); + } + + public void setUp() throws Exception { + super.setUp(); + setServletConfigFile("/WEB-INF/web.xml"); + setConfigFile("tiles","/WEB-INF/struts-config-tiles.xml"); + } + + public void testBadName() { + try { + addRequestParameter("username","deryl"); + addRequestParameter("password","radar"); + setRequestPathInfo("doesnotexist","/tilesForward"); + actionPerform(); + verifyForward("success"); + verifyForwardPath("/layouts/pageLayout.jsp"); + } catch (AssertionFailedError afe) { + return; + } + fail("Should have thrown a JUnit error!"); + } + +} Index: 3rdParty_sources/strutstest/servletunit/struts/tests/TestClearParameters.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/strutstest/servletunit/struts/tests/Attic/TestClearParameters.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/strutstest/servletunit/struts/tests/TestClearParameters.java 17 Aug 2012 15:17:05 -0000 1.1 @@ -0,0 +1,51 @@ +package servletunit.struts.tests; + +import servletunit.struts.MockStrutsTestCase; + +/** + * Created by IntelliJ IDEA. + * User: deryl + * Date: Apr 12, 2003 + * Time: 8:53:11 PM + * To change this template use Options | File Templates. + */ +public class TestClearParameters extends MockStrutsTestCase { + + public TestClearParameters(String testName) { + super(testName); + } + + /** + * Sets up the test fixture for this test. This method creates + * an instance of the ActionServlet, initializes it to validate + * forms and turn off debugging, and creates a mock HttpServletRequest + * and HttpServletResponse object to use in this test. + */ + protected void setUp() throws Exception { + super.setUp(); + setServletConfigFile("/WEB-INF/web.xml"); + } + + public void testClearParameters() { + addRequestParameter("foo","bar"); + addRequestParameter("hi", "there"); + assertEquals("bar",getRequest().getParameter("foo")); + assertEquals("there",getRequest().getParameter("hi")); + clearRequestParameters(); + assertNull(getRequest().getParameter("foo")); + assertNull(getRequest().getParameter("hi")); + } + + public void testClearsRedirectHeaderWhenRequested() { + setRequestPathInfo("test","/testRedirect"); + actionPerform(); + String forward = getActualForward(); + assertEquals("/test/main/success.jsp",forward); + clearRequestParameters(); + addRequestParameter("username","deryl"); + addRequestParameter("password","express"); + setRequestPathInfo("/login"); + actionPerform(); + verifyForward("login"); + } +} Index: 3rdParty_sources/strutstest/servletunit/struts/tests/TestContextParameters.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/strutstest/servletunit/struts/tests/Attic/TestContextParameters.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/strutstest/servletunit/struts/tests/TestContextParameters.java 17 Aug 2012 15:17:06 -0000 1.1 @@ -0,0 +1,54 @@ +// StrutsTestCase - a JUnit extension for testing Struts actions +// within the context of the ActionServlet. +// Copyright (C) 2002 Deryl Seale +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the Apache Software License as +// published by the Apache Software Foundation; either version 1.1 +// of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// Apache Software Foundation Licens for more details. +// +// You may view the full text here: http://www.apache.org/LICENSE.txt + +package servletunit.struts.tests; + +import servletunit.struts.MockStrutsTestCase; +import junit.framework.AssertionFailedError; + +public class TestContextParameters extends MockStrutsTestCase { + + public TestContextParameters(String testName) { + super(testName); + } + + public void setUp() throws Exception { + super.setUp(); + setServletConfigFile("/WEB-INF/web.xml"); + } + + public void testContextParameters() { + setRequestPathInfo("test","/testContextParams"); + actionPerform(); + verifyNoActionErrors(); + } + + public void testContextParametersAbsolutePath() { + setRequestPathInfo("test","/testContextParams"); + setServletConfigFile(System.getProperty("basedir") + "/src/examples/WEB-INF/web.xml"); + actionPerform(); + verifyNoActionErrors(); + } + + public void testContextParametersBadAbsolutePath() { + try { + setServletConfigFile("foo/web.xml"); + } catch (AssertionFailedError afe) { + return; + } + fail("Expected AssertionFailedError!"); + } +} Index: 3rdParty_sources/strutstest/servletunit/struts/tests/TestContextRelative.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/strutstest/servletunit/struts/tests/Attic/TestContextRelative.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/strutstest/servletunit/struts/tests/TestContextRelative.java 17 Aug 2012 15:17:04 -0000 1.1 @@ -0,0 +1,41 @@ +// StrutsTestCase - a JUnit extension for testing Struts actions +// within the context of the ActionServlet. +// Copyright (C) 2002 Deryl Seale +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the Apache Software License as +// published by the Apache Software Foundation; either version 1.1 +// of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// Apache Software Foundation Licens for more details. +// +// You may view the full text here: http://www.apache.org/LICENSE.txt + +package servletunit.struts.tests; + +import junit.framework.AssertionFailedError; +import servletunit.struts.MockStrutsTestCase; + +public class TestContextRelative extends MockStrutsTestCase { + + public TestContextRelative(String testName) { + super(testName); + } + + public void setUp() throws Exception { + super.setUp(); + setServletConfigFile("/WEB-INF/web.xml"); + } + + public void testContextRelativeForward() { + setRequestPathInfo("test","/testContextRelative"); + actionPerform(); + verifyForward("redirect"); + verifyNoActionErrors(); + } + + +} Index: 3rdParty_sources/strutstest/servletunit/struts/tests/TestCustomActionMapping.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/strutstest/servletunit/struts/tests/Attic/TestCustomActionMapping.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/strutstest/servletunit/struts/tests/TestCustomActionMapping.java 17 Aug 2012 15:17:05 -0000 1.1 @@ -0,0 +1,31 @@ +package servletunit.struts.tests; + +import servletunit.struts.MockStrutsTestCase; + +public class TestCustomActionMapping extends MockStrutsTestCase { + + /** + * Sets up the test fixture for this test. This method creates + * an instance of the ActionServlet, initializes it to validate + * forms and turn off debugging, and creates a mock HttpServletRequest + * and HttpServletResponse object to use in this test. + */ + protected void setUp() throws Exception { + super.setUp(); + setServletConfigFile("/WEB-INF/web.xml"); + } + + public void testUsesCustomActionMappingWhenSet() { + setRequestPathInfo("test","/testCustomMapping"); + actionPerform(); + verifyForward("success"); + } +} + +// $Log: TestCustomActionMapping.java,v $ +// Revision 1.2 2004/06/11 15:55:15 deryl +// cleaned up logging. +// +// Revision 1.1 2004/06/10 17:34:43 deryl +// verified bug 955188 +// Index: 3rdParty_sources/strutstest/servletunit/struts/tests/TestDispatchAction.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/strutstest/servletunit/struts/tests/Attic/TestDispatchAction.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/strutstest/servletunit/struts/tests/TestDispatchAction.java 17 Aug 2012 15:17:05 -0000 1.1 @@ -0,0 +1,34 @@ +/* + * User: dxseale + * Date: Nov 8, 2002 + */ +package servletunit.struts.tests; + +import servletunit.struts.MockStrutsTestCase; + +public class TestDispatchAction extends MockStrutsTestCase { + + public TestDispatchAction(String testName) { + super(testName); + } + + public void setUp() throws Exception { + super.setUp(); + setServletConfigFile("/WEB-INF/web.xml"); + } + + public void testDispatchAction() { + addRequestParameter("method","actionOne"); + setRequestPathInfo("test","/testDispatchAction"); + actionPerform(); + verifyNoActionErrors(); + verifyForward("action1"); + addRequestParameter("method","actionTwo"); + setRequestPathInfo("test","/testDispatchAction"); + actionPerform(); + verifyNoActionErrors(); + verifyForward("action2"); + + } + +} Index: 3rdParty_sources/strutstest/servletunit/struts/tests/TestDynaActionForm.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/strutstest/servletunit/struts/tests/Attic/TestDynaActionForm.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/strutstest/servletunit/struts/tests/TestDynaActionForm.java 17 Aug 2012 15:17:04 -0000 1.1 @@ -0,0 +1,42 @@ +// StrutsTestCase - a JUnit extension for testing Struts actions +// within the context of the ActionServlet. +// Copyright (C) 2002 Deryl Seale +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the Apache Software License as +// published by the Apache Software Foundation; either version 1.1 +// of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// Apache Software Foundation Licens for more details. +// +// You may view the full text here: http://www.apache.org/LICENSE.txt + +package servletunit.struts.tests; + +import servletunit.struts.MockStrutsTestCase; + +public class TestDynaActionForm extends MockStrutsTestCase { + + public TestDynaActionForm(String testName) { + super(testName); + } + + public void setUp() throws Exception { + super.setUp(); + setServletConfigFile("/WEB-INF/web.xml"); + } + + public void testForm() { + addRequestParameter("username","deryl"); + addRequestParameter("password","radar"); + setRequestPathInfo("test","/testDynamicAction"); + actionPerform(); + verifyNoActionErrors(); + } + +} + + Index: 3rdParty_sources/strutstest/servletunit/struts/tests/TestGetActionForm.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/strutstest/servletunit/struts/tests/Attic/TestGetActionForm.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/strutstest/servletunit/struts/tests/TestGetActionForm.java 17 Aug 2012 15:17:05 -0000 1.1 @@ -0,0 +1,55 @@ +// StrutsTestCase - a JUnit extension for testing Struts actions +// within the context of the ActionServlet. +// Copyright (C) 2002 Deryl Seale +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the Apache Software License as +// published by the Apache Software Foundation; either version 1.1 +// of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// Apache Software Foundation Licens for more details. +// +// You may view the full text here: http://www.apache.org/LICENSE.txt + +package servletunit.struts.tests; + +import examples.LoginForm; +import org.apache.struts.action.ActionForm; +import servletunit.struts.MockStrutsTestCase; + +public class TestGetActionForm extends MockStrutsTestCase { + + public TestGetActionForm(String testName) { + super(testName); + } + + public void setUp() throws Exception { + super.setUp(); + setServletConfigFile("/WEB-INF/web.xml"); + } + + public void testSuccessfulLogin() { + + addRequestParameter("username","deryl"); + addRequestParameter("password","radar"); + setRequestPathInfo("/login"); + actionPerform(); + verifyForward("success"); + verifyForwardPath("/main/success.jsp"); + assertEquals("deryl",getSession().getAttribute("authentication")); + verifyNoActionErrors(); + ActionForm form = getActionForm(); + assertNotNull(form); + assertEquals(((LoginForm) form).getUsername(),"deryl"); + } + + public static void main(String[] args) { + junit.textui.TestRunner.run(TestGetActionForm.class); + } + + +} + Index: 3rdParty_sources/strutstest/servletunit/struts/tests/TestGetMockObjects.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/strutstest/servletunit/struts/tests/Attic/TestGetMockObjects.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/strutstest/servletunit/struts/tests/TestGetMockObjects.java 17 Aug 2012 15:17:05 -0000 1.1 @@ -0,0 +1,28 @@ +package servletunit.struts.tests; + +import servletunit.struts.MockStrutsTestCase; +import servletunit.HttpServletRequestSimulator; +import servletunit.HttpServletResponseSimulator; + +import java.security.Principal; + +/** + * Created by IntelliJ IDEA. + * User: deryl + * Date: May 21, 2003 + * Time: 2:25:53 PM + * To change this template use Options | File Templates. + */ +public class TestGetMockObjects extends MockStrutsTestCase { + + public TestGetMockObjects(String testName) { + super(testName); + } + + public void testGetMockObjects() { + HttpServletRequestSimulator request = this.getMockRequest(); + request.setUserRole("foo"); + HttpServletResponseSimulator response = this.getMockResponse(); + response.getStatusCode(); + } +} Index: 3rdParty_sources/strutstest/servletunit/struts/tests/TestInputForward.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/strutstest/servletunit/struts/tests/Attic/TestInputForward.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/strutstest/servletunit/struts/tests/TestInputForward.java 17 Aug 2012 15:17:05 -0000 1.1 @@ -0,0 +1,57 @@ +// StrutsTestCase - a JUnit extension for testing Struts actions +// within the context of the ActionServlet. +// Copyright (C) 2002 Deryl Seale +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the Apache Software License as +// published by the Apache Software Foundation; either version 1.1 +// of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// Apache Software Foundation Licens for more details. +// +// You may view the full text here: http://www.apache.org/LICENSE.txt + +package servletunit.struts.tests; + +import junit.framework.AssertionFailedError; +import servletunit.struts.MockStrutsTestCase; + +public class TestInputForward extends MockStrutsTestCase { + + public TestInputForward(String testName) { + super(testName); + } + + public void setUp() throws Exception { + super.setUp(); + setServletConfigFile("/WEB-INF/web.xml"); + } + + public void testInputForward() { + setRequestPathInfo("/login"); + actionPerform(); + verifyActionErrors(new String[] {"error.password.required","error.username.required"}); + verifyInputForward(); + } + + public void testNoInputForward() { + setRequestPathInfo("test","/loginNoInput"); + try { + actionPerform(); + } catch (AssertionFailedError ex) { + return; + } + fail("Should have thrown an error!"); + } + + public void testModuleInputForward() { + addRequestParameter("method","actionThree"); + setRequestPathInfo("test","/testDispatchAction"); + actionPerform(); + verifyNoActionErrors(); + verifyInputForward(); + } +} Index: 3rdParty_sources/strutstest/servletunit/struts/tests/TestMessageAction.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/strutstest/servletunit/struts/tests/Attic/TestMessageAction.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/strutstest/servletunit/struts/tests/TestMessageAction.java 17 Aug 2012 15:17:04 -0000 1.1 @@ -0,0 +1,113 @@ +// StrutsTestCase - a JUnit extension for testing Struts actions +// within the context of the ActionServlet. +// Copyright (C) 2002 Deryl Seale +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the Apache Software License as +// published by the Apache Software Foundation; either version 1.1 +// of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// Apache Software Foundation Licens for more details. +// You may view the full text here: http://www.apache.org/LICENSE.txt + +package servletunit.struts.tests; + +import servletunit.struts.MockStrutsTestCase; +import junit.framework.AssertionFailedError; +import org.apache.struts.Globals; +import org.apache.struts.action.ActionErrors; +import org.apache.struts.action.ActionError; +import org.apache.struts.action.ActionMessage; + +public class TestMessageAction extends MockStrutsTestCase { + + public TestMessageAction(String testName) { + super(testName); + } + + public void setUp() throws Exception { + super.setUp(); + setServletConfigFile("/WEB-INF/web.xml"); + } + + public void testNoMessages() { + addRequestParameter("username","deryl"); + addRequestParameter("password","radar"); + setRequestPathInfo("/login"); + actionPerform(); + verifyForward("success"); + verifyForwardPath("/main/success.jsp"); + assertEquals("deryl",getSession().getAttribute("authentication")); + verifyNoActionMessages(); + } + + public void testMessageExists() { + setRequestPathInfo("test","/testActionMessages"); + actionPerform(); + verifyForward("success"); + verifyActionMessages(new String[] {"test.message"}); + } + + public void testMessageExistsExpectedNone() { + setRequestPathInfo("test","/testActionMessages"); + actionPerform(); + verifyForward("success"); + try { + verifyNoActionMessages(); + } catch (AssertionFailedError afe) { + return; + } + fail("Expected an AssertionFailedError!"); + } + + public void testMessageMismatch() { + setRequestPathInfo("test","/testActionMessages"); + actionPerform(); + verifyForward("success"); + try { + verifyActionMessages(new String[] {"error.password.mismatch"}); + } catch (AssertionFailedError afe) { + return; + } + fail("Expected an AssertionFailedError!"); + } + + public void testExpectedMessagesNoneExist() { + addRequestParameter("username","deryl"); + addRequestParameter("password","radar"); + setRequestPathInfo("/login"); + actionPerform(); + verifyForward("success"); + verifyForwardPath("/main/success.jsp"); + assertEquals("deryl",getSession().getAttribute("authentication")); + try { + verifyActionMessages(new String[] {"test.message"}); + } catch (AssertionFailedError afe) { + return; + } + fail("Expected AssertionFailedError!"); + } + + public void testVerifiesComplexErrorMessageScenario() { + ActionErrors errors = new ActionErrors(); + errors.add("error1",new ActionError("error1")); + errors.add("error2",new ActionError("error2")); + errors.add("error1",new ActionError("error1")); + getRequest().setAttribute(Globals.ERROR_KEY,errors); + try { + verifyActionErrors(new String[] {"error1","error2","error2"}); + } catch (AssertionFailedError ex) { + return; + } + fail("should not have passed!"); + } + + public static void main(String[] args) { + junit.textui.TestRunner.run(TestMessageAction.class); + } + + +} \ No newline at end of file Index: 3rdParty_sources/strutstest/servletunit/struts/tests/TestMessageResourceAction.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/strutstest/servletunit/struts/tests/Attic/TestMessageResourceAction.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/strutstest/servletunit/struts/tests/TestMessageResourceAction.java 17 Aug 2012 15:17:05 -0000 1.1 @@ -0,0 +1,41 @@ +// StrutsTestCase - a JUnit extension for testing Struts actions +// within the context of the ActionServlet. +// Copyright (C) 2002 Deryl Seale +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the Apache Software License as +// published by the Apache Software Foundation; either version 1.1 +// of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// Apache Software Foundation Licens for more details. +// +// You may view the full text here: http://www.apache.org/LICENSE.txt + +package servletunit.struts.tests; + +import servletunit.struts.MockStrutsTestCase; + +public class TestMessageResourceAction extends MockStrutsTestCase { + + public TestMessageResourceAction(String testName) { + super(testName); + } + + public void setUp() throws Exception { + super.setUp(); + setServletConfigFile("/WEB-INF/web.xml"); + } + + public void testGetResources() { + setRequestPathInfo("test","/testMessage"); + actionPerform(); + verifyForward("success"); + verifyNoActionErrors(); + } + + +} + Index: 3rdParty_sources/strutstest/servletunit/struts/tests/TestMockStrutsTestCase.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/strutstest/servletunit/struts/tests/Attic/TestMockStrutsTestCase.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/strutstest/servletunit/struts/tests/TestMockStrutsTestCase.java 17 Aug 2012 15:17:04 -0000 1.1 @@ -0,0 +1,55 @@ +// StrutsTestCase - a JUnit extension for testing Struts actions +// within the context of the ActionServlet. +// Copyright (C) 2002 Deryl Seale +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the Apache Software License as +// published by the Apache Software Foundation; either version 1.1 +// of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// Apache Software Foundation Licens for more details. +// +// You may view the full text here: http://www.apache.org/LICENSE.txt + + +package servletunit.struts.tests; + +import servletunit.struts.MockStrutsTestCase; + +import java.io.File; + +/** + * A Junit test of the MockStrutsTestCase + * @author Sean Pritchard + */ + +public class TestMockStrutsTestCase extends MockStrutsTestCase { + + public TestMockStrutsTestCase(String testCase) { + super(testCase); + } + + public void setUp() throws Exception { + super.setUp(); + setServletConfigFile("/WEB-INF/web.xml"); + } + + public void testSetInitParameter() throws Exception{ + setInitParameter("testName", "testValue"); + assertEquals("testValue", getActionServlet().getInitParameter("testName")); + } + + public void testSetContextDirectory() { + File file = new File(System.getProperty("basedir")); + setContextDirectory(file); + assertEquals(new File(file,"test.html").getAbsolutePath(),getRequest().getRealPath("/test.html")); + } + + public void testGetRealPathNotSet() { + assertNull(getRequest().getRealPath("/test.html")); + } + +} Index: 3rdParty_sources/strutstest/servletunit/struts/tests/TestMultipleActions.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/strutstest/servletunit/struts/tests/Attic/TestMultipleActions.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/strutstest/servletunit/struts/tests/TestMultipleActions.java 17 Aug 2012 15:17:05 -0000 1.1 @@ -0,0 +1,56 @@ +// StrutsTestCase - a JUnit extension for testing Struts actions +// within the context of the ActionServlet. +// Copyright (C) 2002 Deryl Seale +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the Apache Software License as +// published by the Apache Software Foundation; either version 1.1 +// of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// Apache Software Foundation Licens for more details. +// +// You may view the full text here: http://www.apache.org/LICENSE.txt + +package servletunit.struts.tests; + +import servletunit.struts.MockStrutsTestCase; + +public class TestMultipleActions extends MockStrutsTestCase { + + public TestMultipleActions(String testName) { + super(testName); + } + + public void setUp() throws Exception { + super.setUp(); + setServletConfigFile("/WEB-INF/web.xml"); + } + + public void testSuccessfulLogin() { + + addRequestParameter("username","deryl"); + addRequestParameter("password","radar"); + setRequestPathInfo("/login"); + actionPerform(); + verifyForward("success"); + verifyForwardPath("/main/success.jsp"); + assertEquals("deryl",getSession().getAttribute("authentication")); + verifyNoActionErrors(); + clearRequestParameters(); + setRequestPathInfo("/test", "/testContextParams"); + actionPerform(); + verifyNoActionErrors(); + verifyForward("login"); + verifyForwardPath("/login/login.jsp"); + } + + public static void main(String[] args) { + junit.textui.TestRunner.run(TestMultipleActions.class); + } + + +} + Index: 3rdParty_sources/strutstest/servletunit/struts/tests/TestMultipleConfigFiles.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/strutstest/servletunit/struts/tests/Attic/TestMultipleConfigFiles.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/strutstest/servletunit/struts/tests/TestMultipleConfigFiles.java 17 Aug 2012 15:17:05 -0000 1.1 @@ -0,0 +1,29 @@ +package servletunit.struts.tests; + +import servletunit.struts.MockStrutsTestCase; + +public class TestMultipleConfigFiles extends MockStrutsTestCase + { + + protected void setUp() throws Exception { + super.setUp(); + setServletConfigFile("/WEB-INF/web.xml"); + setConfigFile("/WEB-INF/struts-config-tiles.xml,/WEB-INF/struts-config.xml"); + } + + public void testTilesForward() { + addRequestParameter("username","deryl"); + addRequestParameter("password","radar"); + setRequestPathInfo("/tilesForward.do"); + actionPerform(); + verifyForward("success"); + verifyForwardPath("/layouts/pageLayout.jsp"); + verifyTilesForward("success","page.library"); + clearRequestParameters(); + addRequestParameter("username","deryl"); + addRequestParameter("password","radar"); + setRequestPathInfo("/login"); + actionPerform(); + verifyForward("success"); + } +} Index: 3rdParty_sources/strutstest/servletunit/struts/tests/TestNoRequestPathInfo.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/strutstest/servletunit/struts/tests/Attic/TestNoRequestPathInfo.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/strutstest/servletunit/struts/tests/TestNoRequestPathInfo.java 17 Aug 2012 15:17:05 -0000 1.1 @@ -0,0 +1,55 @@ +// StrutsTestCase - a JUnit extension for testing Struts actions +// within the context of the ActionServlet. +// Copyright (C) 2002 Deryl Seale +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the Apache Software License as +// published by the Apache Software Foundation; either version 1.1 +// of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// Apache Software Foundation Licens for more details. +// +// You may view the full text here: http://www.apache.org/LICENSE.txt +package servletunit.struts.tests; + +import servletunit.struts.MockStrutsTestCase; +import java.io.File; +/** + * + *

Title: TestNoRequestPathInfo

+ *

Description: Confirms correct behavior if + * actionPerfoem() is called prior to calling + * setRequestPathInfo().

+ *

Copyright: Copyright (c) 2003

+ * @author Sean Pritchard + * @version 1.0 + */ +public class TestNoRequestPathInfo extends MockStrutsTestCase { + + public TestNoRequestPathInfo() { + } + + public void setUp() throws Exception { + super.setUp(); + this.setContextDirectory(new File(System.getProperty("basedir") + "/src/examples")); + setConfigFile("/WEB-INF/struts-config-test.xml"); + } + + /** + * this test assumes that web.xml and struts-config.xml + * can be found. If these files are found, + * but no request path is set prior to calling + * actionPerform(), we expect an IllegalStateException + */ + public void testNoRequestPathInfo(){ + try{ + actionPerform(); + fail("IllegalStateException expected"); + }catch(IllegalStateException e){ + //expected + } + } +} \ No newline at end of file Index: 3rdParty_sources/strutstest/servletunit/struts/tests/TestNullAction.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/strutstest/servletunit/struts/tests/Attic/TestNullAction.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/strutstest/servletunit/struts/tests/TestNullAction.java 17 Aug 2012 15:17:05 -0000 1.1 @@ -0,0 +1,29 @@ +package servletunit.struts.tests; + +import servletunit.struts.MockStrutsTestCase; + +/** + * Created by IntelliJ IDEA. + * User: deryl + * Date: Apr 13, 2003 + * Time: 12:07:32 PM + * To change this template use Options | File Templates. + */ +public class TestNullAction extends MockStrutsTestCase { + + public TestNullAction(String testName) { + super(testName); + } + + public void setUp() throws Exception { + super.setUp(); + setServletConfigFile("/WEB-INF/web.xml"); + } + + public void testNullAction() { + setRequestPathInfo("test","/testNullAction.do"); + actionPerform(); + verifyForward(null); + verifyForwardPath(null); + } +} Index: 3rdParty_sources/strutstest/servletunit/struts/tests/TestNullPointerAction.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/strutstest/servletunit/struts/tests/Attic/TestNullPointerAction.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/strutstest/servletunit/struts/tests/TestNullPointerAction.java 17 Aug 2012 15:17:05 -0000 1.1 @@ -0,0 +1,69 @@ +// StrutsTestCase - a JUnit extension for testing Struts actions +// within the context of the ActionServlet. +// Copyright (C) 2002 Deryl Seale +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the Apache Software License as +// published by the Apache Software Foundation; either version 1.1 +// of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// Apache Software Foundation Licens for more details. +// +// You may view the full text here: http://www.apache.org/LICENSE.txt +package servletunit.struts.tests; + +import servletunit.struts.*; +import java.io.File; + +/** + *

Title: NullPointerActionTest

+ *

Description: Tests to confirm a NullPointerException + * thrown from a misbehaving action reaches the test.

+ *

Copyright: Copyright (c) 2003

+ * @author Sean Pritchard + * @version 1.0 + */ +public class TestNullPointerAction extends MockStrutsTestCase { + + public TestNullPointerAction() { + } + + public void setUp() throws Exception { + super.setUp(); + this.setContextDirectory(new File(System.getProperty("basedir") + "/src/examples")); + setConfigFile("/WEB-INF/struts-config-test.xml"); + } + + public void testNullPointer() throws Exception{ + try{ + this.setRequestPathInfo("/testNullPointer"); + this.actionPerform(); + fail("Exception expected"); + }catch(ExceptionDuringTestError e){ + //uncomment this to see a sample stack trace + //that users will see if their action throws an exception +// throw e; + } + } + + public void testNullPointerFromForm() throws Exception{ + try{ + this.setRequestPathInfo("/testNullPointerForm"); + this.actionPerform(); + fail("Exception expected"); + }catch(ExceptionDuringTestError e){ + //uncomment this to see a sample stack trace + //that users will see if their action throws an exception +// throw e; + } + } + + + public static void main(String[] args) { + junit.textui.TestRunner.run(TestNullPointerAction.class); + } + +} Index: 3rdParty_sources/strutstest/servletunit/struts/tests/TestRedirectAction.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/strutstest/servletunit/struts/tests/Attic/TestRedirectAction.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/strutstest/servletunit/struts/tests/TestRedirectAction.java 17 Aug 2012 15:17:05 -0000 1.1 @@ -0,0 +1,74 @@ +// StrutsTestCase - a JUnit extension for testing Struts actions +// within the context of the ActionServlet. +// Copyright (C) 2002 Deryl Seale +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the Apache Software License as +// published by the Apache Software Foundation; either version 1.1 +// of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// Apache Software Foundation Licens for more details. +// +// You may view the full text here: http://www.apache.org/LICENSE.txt + +package servletunit.struts.tests; + +import junit.framework.AssertionFailedError; +import servletunit.struts.MockStrutsTestCase; + +public class TestRedirectAction extends MockStrutsTestCase { + + public TestRedirectAction(String testName) { + super(testName); + } + + public void setUp() throws Exception { + super.setUp(); + setServletConfigFile("/WEB-INF/web.xml"); + } + + public void testVerifyRedirect() { + setRequestPathInfo("test","/testRedirect"); + actionPerform(); + verifyForward("redirect"); + verifyForwardPath("/test/main/success.jsp"); + verifyNoActionErrors(); + } + + /** + * Confirms verifyForward works correctly when the redirect path + * is a relative (not absolute) URL + */ + public void testRelativeRedirect() { + setRequestPathInfo("test","/testRelativeRedirect"); + actionPerform(); + verifyForward("redirect"); + verifyForwardPath("/test/main/success.jsp"); + verifyNoActionErrors(); + } + + //todo: this test is for a future enhancement. +// public void testVerifiesRedirectedExternalURL() { +// setRequestPathInfo("test","/testRedirectToExternalURL"); +// actionPerform(); +// verifyForwardPath("http://www.yahoo.com"); +// verifyForward("redirect"); +// } + + public void testVerifyRedirectFail() { + try { + setRequestPathInfo("test","/testRedirect"); + actionPerform(); + verifyForward("login"); + verifyNoActionErrors(); + } catch (AssertionFailedError e) { + return; + } + fail("We are apparently getting the same redirects, when they should be different."); + } + + +} Index: 3rdParty_sources/strutstest/servletunit/struts/tests/TestResponseStatus.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/strutstest/servletunit/struts/tests/Attic/TestResponseStatus.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/strutstest/servletunit/struts/tests/TestResponseStatus.java 17 Aug 2012 15:17:05 -0000 1.1 @@ -0,0 +1,40 @@ +package servletunit.struts.tests; + +import servletunit.struts.MockStrutsTestCase; +import servletunit.HttpServletResponseSimulator; +import junit.framework.AssertionFailedError; + +/** + * Created by IntelliJ IDEA. + * User: deryl + * Date: May 20, 2003 + * Time: 5:16:57 PM + * To change this template use Options | File Templates. + */ +public class TestResponseStatus extends MockStrutsTestCase { + + public TestResponseStatus(String testName) { + super(testName); + } + + public void setUp() throws Exception { + super.setUp(); + setServletConfigFile("/WEB-INF/web.xml"); + } + + public void testResponseCode() { + setRequestPathInfo("/badActionPath"); + try { + actionPerform(); + } catch (AssertionFailedError afe) { + int statusCode = ((HttpServletResponseSimulator) getResponse()).getStatusCode(); + // todo: backwards compatible with struts 1.1 + assertTrue("unexpected response code",statusCode == 404 || statusCode == 400); + return; + } + fail("expected some error code!"); + + } + + +} Index: 3rdParty_sources/strutstest/servletunit/struts/tests/TestSetActionForm.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/strutstest/servletunit/struts/tests/Attic/TestSetActionForm.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/strutstest/servletunit/struts/tests/TestSetActionForm.java 17 Aug 2012 15:17:06 -0000 1.1 @@ -0,0 +1,91 @@ +// StrutsTestCase - a JUnit extension for testing Struts actions +// within the context of the ActionServlet. +// Copyright (C) 2002 Deryl Seale +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the Apache Software License as +// published by the Apache Software Foundation; either version 1.1 +// of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// Apache Software Foundation Licens for more details. +// +// You may view the full text here: http://www.apache.org/LICENSE.txt + +package servletunit.struts.tests; + +import servletunit.struts.MockStrutsTestCase; +import examples.LoginForm; + +public class TestSetActionForm extends MockStrutsTestCase { + + public TestSetActionForm(String testName) { + super(testName); + } + + public void setUp() throws Exception { + super.setUp(); + setServletConfigFile("/WEB-INF/web.xml"); + } + + public void testNonModuleSetActionForm() { + LoginForm form = new LoginForm(); + form.setUsername("deryl"); + form.setPassword("radar"); + setRequestPathInfo("/login"); + setActionForm(form); + actionPerform(); + verifyNoActionErrors(); + verifyForward("success"); + verifyForwardPath("/main/success.jsp"); + } + + public void testSetActionForm() { + ComplexForm form = new ComplexForm(); + form.setUsername("deryl"); + form.setPassword("radar"); + form.setComplexObject(new Object()); + setRequestPathInfo("test","/testSetActionForm"); + setActionForm(form); + actionPerform(); + verifyForward("success"); + verifyForwardPath("/test/main/success.jsp"); + verifyNoActionErrors(); + } + + public void testFormReset() { + ComplexForm form = new ComplexForm(); + form.setUsername("deryl"); + form.setPassword("radar"); + form.setComplexObject(new Object()); + setRequestPathInfo("test","/testSetActionForm"); + addRequestParameter("test.reset","true"); + setActionForm(form); + actionPerform(); + verifyForward("login"); + verifyForwardPath("/login/login.jsp"); + verifyActionErrors(new String[] {"error.password.mismatch"}); + } + + public void testSetActionFormBeforeSettingRequestPathFails() { + ComplexForm form = new ComplexForm(); + form.setUsername("deryl"); + form.setPassword("radar"); + form.setComplexObject(new Object()); + try { + setActionForm(form); + } catch (IllegalStateException ise) { + return; + } + fail("should have thrown IllegalStateException"); + } + + public static void main(String[] args) { + junit.textui.TestRunner.run(TestSetActionForm.class); + } + + +} + Index: 3rdParty_sources/strutstest/servletunit/struts/tests/TestSimpleForward.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/strutstest/servletunit/struts/tests/Attic/TestSimpleForward.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/strutstest/servletunit/struts/tests/TestSimpleForward.java 17 Aug 2012 15:17:06 -0000 1.1 @@ -0,0 +1,37 @@ +// StrutsTestCase - a JUnit extension for testing Struts actions +// within the context of the ActionServlet. +// Copyright (C) 2002 Deryl Seale +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the Apache Software License as +// published by the Apache Software Foundation; either version 1.1 +// of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// Apache Software Foundation Licens for more details. +// +// You may view the full text here: http://www.apache.org/LICENSE.txt + +package servletunit.struts.tests; + +import servletunit.struts.MockStrutsTestCase; + +public class TestSimpleForward extends MockStrutsTestCase { + + public TestSimpleForward(String testName) { + super(testName); + } + + public void setUp() throws Exception { + super.setUp(); + setServletConfigFile("/WEB-INF/web.xml"); + } + + public void testSimpleForward() { + setRequestPathInfo("test","/testSimpleForward"); + actionPerform(); + } + +} Index: 3rdParty_sources/strutstest/servletunit/struts/tests/TestTilesForward.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/strutstest/servletunit/struts/tests/Attic/TestTilesForward.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/strutstest/servletunit/struts/tests/TestTilesForward.java 17 Aug 2012 15:17:06 -0000 1.1 @@ -0,0 +1,85 @@ +// StrutsTestCase - a JUnit extension for testing Struts actions +// within the context of the ActionServlet. +// Copyright (C) 2002 Deryl Seale +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the Apache Software License as +// published by the Apache Software Foundation; either version 1.1 +// of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// Apache Software Foundation Licens for more details. +// +// You may view the full text here: http://www.apache.org/LICENSE.txt + +package servletunit.struts.tests; + +import servletunit.struts.MockStrutsTestCase; +import junit.framework.AssertionFailedError; + +public class TestTilesForward extends MockStrutsTestCase { + + public TestTilesForward(String testName) { + super(testName); + } + + public void setUp() throws Exception { + super.setUp(); + setConfigFile("tiles","/WEB-INF/struts-config-tiles.xml"); + setServletConfigFile("/WEB-INF/web.xml"); + setConfigFile("/WEB-INF/struts-config.xml"); + } + + + public void testTilesForward() { + addRequestParameter("username","deryl"); + addRequestParameter("password","radar"); + setRequestPathInfo("tiles","/tilesForward.do"); + actionPerform(); + verifyForward("success"); + verifyForwardPath("/layouts/pageLayout.jsp"); + verifyTilesForward("success","page.library"); + } + + public void testTilesInputForward() { + setRequestPathInfo("tiles","/tilesInputForward.do"); + actionPerform(); + verifyInputForward(); + verifyInputTilesForward("page.library"); + } + + public void testTileForwardFail() { + addRequestParameter("username","deryl"); + addRequestParameter("password","radar"); + setRequestPathInfo("tiles","/tilesForward.do"); + actionPerform(); + verifyForward("success"); + verifyForwardPath("/layouts/pageLayout.jsp"); + try { + verifyTilesForward("success","foo.fail"); + } catch (AssertionFailedError afe) { + return; + } + fail("Should have failed."); + } + +// todo: this test is failing because tiles verify doesn't work properly +// public void testTileForwardFailDefinitionExists() { +// addRequestParameter("username","deryl"); +// addRequestParameter("password","radar"); +// setRequestPathInfo("tiles","/tilesForward.do"); +// actionPerform(); +// verifyForward("success"); +// verifyForwardPath("/layouts/pageLayout.jsp"); +// try { +// verifyTilesForward("failure","another.page"); +// } catch (AssertionFailedError afe) { +// return; +// } +// fail("Should have failed."); +// } + + +} Index: 3rdParty_sources/strutstest/servletunit/struts/tests/TestTokenAction.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/strutstest/servletunit/struts/tests/Attic/TestTokenAction.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/strutstest/servletunit/struts/tests/TestTokenAction.java 17 Aug 2012 15:17:05 -0000 1.1 @@ -0,0 +1,44 @@ +// StrutsTestCase - a JUnit extension for testing Struts actions +// within the context of the ActionServlet. +// Copyright (C) 2002 Deryl Seale +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the Apache Software License as +// published by the Apache Software Foundation; either version 1.1 +// of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// Apache Software Foundation Licens for more details. +// +// You may view the full text here: http://www.apache.org/LICENSE.txt + +package servletunit.struts.tests; + +import org.apache.struts.action.Action; +import org.apache.struts.taglib.html.Constants; +import org.apache.struts.Globals; +import servletunit.struts.MockStrutsTestCase; + +public class TestTokenAction extends MockStrutsTestCase { + + public TestTokenAction(String testName) { + super(testName); + } + + public void setUp() throws Exception { + super.setUp(); + setServletConfigFile("/WEB-INF/web.xml"); + } + + public void testTransactionToken() { + addRequestParameter(Constants.TOKEN_KEY, "test_token"); + getSession().setAttribute(Globals.TRANSACTION_TOKEN_KEY, "test_token"); + setRequestPathInfo("test","/testToken"); + actionPerform(); + verifyNoActionErrors(); + } + + +} Index: 3rdParty_sources/strutstest/servletunit/struts/tests/TestUserAction.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/strutstest/servletunit/struts/tests/Attic/TestUserAction.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/strutstest/servletunit/struts/tests/TestUserAction.java 17 Aug 2012 15:17:05 -0000 1.1 @@ -0,0 +1,43 @@ +// StrutsTestCase - a JUnit extension for testing Struts actions +// within the context of the ActionServlet. +// Copyright (C) 2002 Deryl Seale +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the Apache Software License as +// published by the Apache Software Foundation; either version 1.1 +// of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// Apache Software Foundation Licens for more details. +// +// You may view the full text here: http://www.apache.org/LICENSE.txt + +package servletunit.struts.tests; + +import servletunit.struts.MockStrutsTestCase; + +/** + * This class is reserved for quickly testing out other + * user's actions, to help in debugging their problems. + * It is deliberately checked in empty, as it is a place- + * holder. + */ +public class TestUserAction extends MockStrutsTestCase { + + /** + * Sets up the test fixture for this test. This method creates + * an instance of the ActionServlet, initializes it to validate + * forms and turn off debugging, and creates a mock HttpServletRequest + * and HttpServletResponse object to use in this test. + */ + protected void setUp() throws Exception { + super.setUp(); + setServletConfigFile("/WEB-INF/web.xml"); + } + + public void testAction() { + } + +} Index: 3rdParty_sources/strutstest/servletunit/struts/tests/TokenAction.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/strutstest/servletunit/struts/tests/Attic/TokenAction.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/strutstest/servletunit/struts/tests/TokenAction.java 17 Aug 2012 15:17:05 -0000 1.1 @@ -0,0 +1,40 @@ +// StrutsTestCase - a JUnit extension for testing Struts actions +// within the context of the ActionServlet. +// Copyright (C) 2002 Deryl Seale +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the Apache Software License as +// published by the Apache Software Foundation; either version 1.1 +// of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// Apache Software Foundation Licens for more details. +// +// You may view the full text here: http://www.apache.org/LICENSE.txt + +package servletunit.struts.tests; + +import org.apache.struts.action.*; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +public class TokenAction extends Action { + + public ActionForward execute(ActionMapping mapping, + ActionForm form, + HttpServletRequest request, + HttpServletResponse response) { + + ActionErrors errors = new ActionErrors(); + + if (!isTokenValid(request,true)) { + errors.add("password",new ActionMessage("error.token")); + saveErrors(request,errors); + } + return mapping.findForward("login"); + } + +} Index: 3rdParty_sources/strutstest/servletunit/struts/tests/UserAction.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/strutstest/servletunit/struts/tests/Attic/UserAction.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/strutstest/servletunit/struts/tests/UserAction.java 17 Aug 2012 15:17:05 -0000 1.1 @@ -0,0 +1,40 @@ +// StrutsTestCase - a JUnit extension for testing Struts actions +// within the context of the ActionServlet. +// Copyright (C) 2002 Deryl Seale +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the Apache Software License as +// published by the Apache Software Foundation; either version 1.1 +// of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// Apache Software Foundation Licens for more details. +// +// You may view the full text here: http://www.apache.org/LICENSE.txt + +package servletunit.struts.tests; + +import org.apache.struts.action.*; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +public class UserAction extends Action { + + /** + * This class is reserved for quickly testing out other + * user's actions, to help in debugging their problems. + * It is deliberately checked in empty, as it is a place- + * holder. + */ + public ActionForward execute(ActionMapping mapping, + ActionForm form, + HttpServletRequest request, + HttpServletResponse response) { + + return null; + } + +} Index: 3rdParty_sources/strutstest/servletunit/struts/tests/cactus/TestAbsolutePath.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/strutstest/servletunit/struts/tests/cactus/Attic/TestAbsolutePath.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/strutstest/servletunit/struts/tests/cactus/TestAbsolutePath.java 17 Aug 2012 15:17:07 -0000 1.1 @@ -0,0 +1,72 @@ +// StrutsTestCase - a JUnit extension for testing Struts actions +// within the context of the ActionServlet. +// Copyright (C) 2002 Deryl Seale +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the Apache Software License as +// published by the Apache Software Foundation; either version 1.1 +// of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// Apache Software Foundation Licens for more details. +// +// You may view the full text here: http://www.apache.org/LICENSE.txt + +package servletunit.struts.tests.cactus; + +import servletunit.struts.CactusStrutsTestCase; +import org.apache.cactus.WebRequest; + +import javax.servlet.http.Cookie; + +public class TestAbsolutePath extends CactusStrutsTestCase { + + static final String COOKIE_NAME = "config_file"; + + public TestAbsolutePath(String testName) { + super(testName); + } + + public void beginSuccessfulLogin(WebRequest theRequest) { + if (logger.isDebugEnabled()) + logger.debug("setting cookie to " + System.getProperty("basedir") + "/src/examples/WEB-INF/struts-config.xml"); + theRequest.addCookie(COOKIE_NAME, System.getProperty("basedir") + "/src/examples/WEB-INF/struts-config.xml"); + } + + public void testSuccessfulLogin() { + String fileName = getCookieValue(request.getCookies(), COOKIE_NAME); + setConfigFile(fileName); + addRequestParameter("username","deryl"); + addRequestParameter("password","radar"); + setRequestPathInfo("/login"); + actionPerform(); + verifyForward("success"); + verifyForwardPath("/main/success.jsp"); + assertEquals("deryl",getSession().getAttribute("authentication")); + verifyNoActionErrors(); + } + + private String getCookieValue (Cookie[] cookies, String name) { + String value = null; + if (cookies != null) { + for (int i = 0; i < cookies.length; i++) { + logger.debug ("checking cookie " + cookies[i].getName()); + + if (cookies[i].getName().equals(name)) { + value = cookies[i].getValue(); + break; + } + } + } + return value; + } + + public static void main(String[] args) { + junit.textui.TestRunner.run(TestAbsolutePath.class); + } + + +} + Index: 3rdParty_sources/strutstest/servletunit/struts/tests/cactus/TestBadModuleName.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/strutstest/servletunit/struts/tests/cactus/Attic/TestBadModuleName.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/strutstest/servletunit/struts/tests/cactus/TestBadModuleName.java 17 Aug 2012 15:17:08 -0000 1.1 @@ -0,0 +1,39 @@ +package servletunit.struts.tests.cactus; + +import servletunit.struts.MockStrutsTestCase; +import servletunit.struts.CactusStrutsTestCase; +import junit.framework.AssertionFailedError; + +/** + * Created by IntelliJ IDEA. + * User: deryl + * Date: Apr 28, 2003 + * Time: 9:26:32 AM + * To change this template use Options | File Templates. + */ +public class TestBadModuleName extends CactusStrutsTestCase { + + public TestBadModuleName(String testName) { + super(testName); + } + + public void setUp() throws Exception { + super.setUp(); + setConfigFile("tiles","/WEB-INF/struts-config-tiles.xml"); + } + + public void testBadName() { + try { + addRequestParameter("username","deryl"); + addRequestParameter("password","radar"); + setRequestPathInfo("doesnotexist","/tilesForward"); + actionPerform(); + verifyForward("success"); + verifyForwardPath("/layouts/pageLayout.jsp"); + } catch (AssertionFailedError afe) { + return; + } + fail("Should have thrown a JUnit error!"); + } + +} Index: 3rdParty_sources/strutstest/servletunit/struts/tests/cactus/TestClearParameters.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/strutstest/servletunit/struts/tests/cactus/Attic/TestClearParameters.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/strutstest/servletunit/struts/tests/cactus/TestClearParameters.java 17 Aug 2012 15:17:08 -0000 1.1 @@ -0,0 +1,31 @@ +package servletunit.struts.tests.cactus; + +import servletunit.struts.CactusStrutsTestCase; + +import java.util.Map; + +/** + * Created by IntelliJ IDEA. + * User: deryl + * Date: Apr 12, 2003 + * Time: 8:53:11 PM + * To change this template use Options | File Templates. + */ +public class TestClearParameters extends CactusStrutsTestCase { + + public TestClearParameters(String testName) { + super(testName); + } + + public void testClearParameters() { + addRequestParameter("foo","bar"); + addRequestParameter("hi", "there"); + assertEquals("bar",getRequest().getParameter("foo")); + assertEquals("there",getRequest().getParameter("hi")); + clearRequestParameters(); + assertNull(getRequest().getParameter("foo")); + assertNull(getRequest().getParameter("hi")); + } + + +} Index: 3rdParty_sources/strutstest/servletunit/struts/tests/cactus/TestContextParameters.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/strutstest/servletunit/struts/tests/cactus/Attic/TestContextParameters.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/strutstest/servletunit/struts/tests/cactus/TestContextParameters.java 17 Aug 2012 15:17:07 -0000 1.1 @@ -0,0 +1,33 @@ +// StrutsTestCase - a JUnit extension for testing Struts actions +// within the context of the ActionServlet. +// Copyright (C) 2002 Deryl Seale +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the Apache Software License as +// published by the Apache Software Foundation; either version 1.1 +// of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// Apache Software Foundation Licens for more details. +// +// You may view the full text here: http://www.apache.org/LICENSE.txt + +package servletunit.struts.tests.cactus; + +import servletunit.struts.CactusStrutsTestCase; + +public class TestContextParameters extends CactusStrutsTestCase { + + public TestContextParameters(String testName) { + super(testName); + } + + public void testContextParameters() { + setRequestPathInfo("test","/testContextParams"); + actionPerform(); + verifyNoActionErrors(); + } + +} Index: 3rdParty_sources/strutstest/servletunit/struts/tests/cactus/TestContextRelative.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/strutstest/servletunit/struts/tests/cactus/Attic/TestContextRelative.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/strutstest/servletunit/struts/tests/cactus/TestContextRelative.java 17 Aug 2012 15:17:08 -0000 1.1 @@ -0,0 +1,34 @@ +// StrutsTestCase - a JUnit extension for testing Struts actions +// within the context of the ActionServlet. +// Copyright (C) 2002 Deryl Seale +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the Apache Software License as +// published by the Apache Software Foundation; either version 1.1 +// of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// Apache Software Foundation Licens for more details. +// +// You may view the full text here: http://www.apache.org/LICENSE.txt + +package servletunit.struts.tests.cactus; + +import servletunit.struts.CactusStrutsTestCase; + +public class TestContextRelative extends CactusStrutsTestCase { + + public TestContextRelative(String testName) { + super(testName); + } + + public void testContextRelativeForward() { + setRequestPathInfo("test","/testContextRelative"); + actionPerform(); + verifyForward("redirect"); + verifyNoActionErrors(); + } + +} Index: 3rdParty_sources/strutstest/servletunit/struts/tests/cactus/TestDispatchAction.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/strutstest/servletunit/struts/tests/cactus/Attic/TestDispatchAction.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/strutstest/servletunit/struts/tests/cactus/TestDispatchAction.java 17 Aug 2012 15:17:08 -0000 1.1 @@ -0,0 +1,28 @@ +/* + * User: dxseale + * Date: Nov 8, 2002 + */ +package servletunit.struts.tests.cactus; + +import servletunit.struts.CactusStrutsTestCase; + +public class TestDispatchAction extends CactusStrutsTestCase { + + public TestDispatchAction(String testName) { + super(testName); + } + + public void testDispatchAction() { + addRequestParameter("method","actionOne"); + setRequestPathInfo("test","/testDispatchAction"); + actionPerform(); + verifyNoActionErrors(); + verifyForward("action1"); + addRequestParameter("method","actionTwo"); + setRequestPathInfo("test","/testDispatchAction"); + actionPerform(); + verifyNoActionErrors(); + verifyForward("action2"); + } + +} Index: 3rdParty_sources/strutstest/servletunit/struts/tests/cactus/TestDynaActionForm.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/strutstest/servletunit/struts/tests/cactus/Attic/TestDynaActionForm.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/strutstest/servletunit/struts/tests/cactus/TestDynaActionForm.java 17 Aug 2012 15:17:07 -0000 1.1 @@ -0,0 +1,37 @@ +// StrutsTestCase - a JUnit extension for testing Struts actions +// within the context of the ActionServlet. +// Copyright (C) 2002 Deryl Seale +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the Apache Software License as +// published by the Apache Software Foundation; either version 1.1 +// of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// Apache Software Foundation Licens for more details. +// +// You may view the full text here: http://www.apache.org/LICENSE.txt + +package servletunit.struts.tests.cactus; + +import servletunit.struts.CactusStrutsTestCase; + +public class TestDynaActionForm extends CactusStrutsTestCase { + + public TestDynaActionForm(String testName) { + super(testName); + } + + public void testForm() { + addRequestParameter("username","deryl"); + addRequestParameter("password","radar"); + setRequestPathInfo("test","/testDynamicAction"); + actionPerform(); + verifyNoActionErrors(); + } + +} + + Index: 3rdParty_sources/strutstest/servletunit/struts/tests/cactus/TestGetActionForm.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/strutstest/servletunit/struts/tests/cactus/Attic/TestGetActionForm.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/strutstest/servletunit/struts/tests/cactus/TestGetActionForm.java 17 Aug 2012 15:17:07 -0000 1.1 @@ -0,0 +1,49 @@ +// StrutsTestCase - a JUnit extension for testing Struts actions +// within the context of the ActionServlet. +// Copyright (C) 2002 Deryl Seale +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the Apache Software License as +// published by the Apache Software Foundation; either version 1.1 +// of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// Apache Software Foundation Licens for more details. +// +// You may view the full text here: http://www.apache.org/LICENSE.txt + +package servletunit.struts.tests.cactus; + +import examples.LoginForm; +import org.apache.struts.action.ActionForm; +import servletunit.struts.CactusStrutsTestCase; + +public class TestGetActionForm extends CactusStrutsTestCase { + + public TestGetActionForm(String testName) { + super(testName); + } + + public void testSuccessfulLogin() { + + addRequestParameter("username","deryl"); + addRequestParameter("password","radar"); + setRequestPathInfo("/login"); + actionPerform(); + verifyForward("success"); + verifyForwardPath("/main/success.jsp"); + assertEquals("deryl",(String) getSession().getAttribute("authentication")); + verifyNoActionErrors(); + ActionForm form = getActionForm(); + assertNotNull(form); + assertEquals(((LoginForm) form).getUsername(),"deryl"); + } + + public static void main(String[] args) { + junit.textui.TestRunner.run(TestGetActionForm.class); + } + +} + Index: 3rdParty_sources/strutstest/servletunit/struts/tests/cactus/TestGetRequestParameterMap.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/strutstest/servletunit/struts/tests/cactus/Attic/TestGetRequestParameterMap.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/strutstest/servletunit/struts/tests/cactus/TestGetRequestParameterMap.java 17 Aug 2012 15:17:08 -0000 1.1 @@ -0,0 +1,17 @@ +package servletunit.struts.tests.cactus; + +import servletunit.struts.CactusStrutsTestCase; + +import java.util.Map; + +public class TestGetRequestParameterMap extends CactusStrutsTestCase { + + public void testGetParameterMap() { + addRequestParameter("foo","bar"); + assertEquals("bar",getRequest().getParameter("foo")); + Map parameterMap = getRequest().getParameterMap(); + assertNotNull(parameterMap); + assertEquals("bar",parameterMap.get("foo")); + } + +} Index: 3rdParty_sources/strutstest/servletunit/struts/tests/cactus/TestInputForward.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/strutstest/servletunit/struts/tests/cactus/Attic/TestInputForward.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/strutstest/servletunit/struts/tests/cactus/TestInputForward.java 17 Aug 2012 15:17:07 -0000 1.1 @@ -0,0 +1,43 @@ +// StrutsTestCase - a JUnit extension for testing Struts actions +// within the context of the ActionServlet. +// Copyright (C) 2002 Deryl Seale +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the Apache Software License as +// published by the Apache Software Foundation; either version 1.1 +// of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// Apache Software Foundation Licens for more details. +// +// You may view the full text here: http://www.apache.org/LICENSE.txt + +package servletunit.struts.tests.cactus; + +import servletunit.struts.CactusStrutsTestCase; + +public class TestInputForward extends CactusStrutsTestCase { + + public TestInputForward(String testName) { + super(testName); + } + + public void testInputForward() { + setRequestPathInfo("/login"); + actionPerform(); + verifyActionErrors(new String[] {"error.password.required","error.username.required"}); + verifyInputForward(); + } + + public void testModuleInputForward() { + addRequestParameter("method","actionThree"); + setRequestPathInfo("test","/testDispatchAction"); + actionPerform(); + verifyNoActionErrors(); + verifyInputForward(); + } + + +} Index: 3rdParty_sources/strutstest/servletunit/struts/tests/cactus/TestMessageAction.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/strutstest/servletunit/struts/tests/cactus/Attic/TestMessageAction.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/strutstest/servletunit/struts/tests/cactus/TestMessageAction.java 17 Aug 2012 15:17:07 -0000 1.1 @@ -0,0 +1,92 @@ +// StrutsTestCase - a JUnit extension for testing Struts actions +// within the context of the ActionServlet. +// Copyright (C) 2002 Deryl Seale +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the Apache Software License as +// published by the Apache Software Foundation; either version 1.1 +// of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// Apache Software Foundation Licens for more details. +// test +// You may view the full text here: http://www.apache.org/LICENSE.txt + +package servletunit.struts.tests.cactus; + +import servletunit.struts.CactusStrutsTestCase; +import junit.framework.AssertionFailedError; + +public class TestMessageAction extends CactusStrutsTestCase { + + public TestMessageAction(String testName) { + super(testName); + } + + public void testNoMessages() { + addRequestParameter("username","deryl"); + addRequestParameter("password","radar"); + setRequestPathInfo("/login"); + actionPerform(); + verifyForward("success"); + verifyForwardPath("/main/success.jsp"); + assertEquals("deryl",getSession().getAttribute("authentication")); + verifyNoActionMessages(); + } + + public void testMessageExists() { + setRequestPathInfo("test","/testActionMessages"); + actionPerform(); + verifyForward("success"); + verifyActionMessages(new String[] {"test.message"}); + } + + public void testMessageExistsExpectedNone() { + setRequestPathInfo("test","/testActionMessages"); + actionPerform(); + verifyForward("success"); + try { + verifyNoActionMessages(); + } catch (AssertionFailedError afe) { + return; + } + fail("Expected an AssertionFailedError!"); + } + + public void testMessageMismatch() { + setRequestPathInfo("test","/testActionMessages"); + actionPerform(); + verifyForward("success"); + try { + verifyActionMessages(new String[] {"error.password.mismatch"}); + } catch (AssertionFailedError afe) { + return; + } + fail("Expected an AssertionFailedError!"); + } + + public void testExpectedMessagesNoneExist() { + addRequestParameter("username","deryl"); + addRequestParameter("password","radar"); + setRequestPathInfo("/login"); + actionPerform(); + verifyForward("success"); + verifyForwardPath("/main/success.jsp"); + assertEquals("deryl",getSession().getAttribute("authentication")); + try { + verifyActionMessages(new String[] {"test.message"}); + } catch (AssertionFailedError afe) { + return; + } + fail("Expected AssertionFailedError!"); + } + + public static void main(String[] args) { + junit.textui.TestRunner.run(TestMessageAction.class); + } + + +} + Index: 3rdParty_sources/strutstest/servletunit/struts/tests/cactus/TestMessageResourceAction.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/strutstest/servletunit/struts/tests/cactus/Attic/TestMessageResourceAction.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/strutstest/servletunit/struts/tests/cactus/TestMessageResourceAction.java 17 Aug 2012 15:17:08 -0000 1.1 @@ -0,0 +1,43 @@ +// StrutsTestCase - a JUnit extension for testing Struts actions +// within the context of the ActionServlet. +// Copyright (C) 2002 Deryl Seale +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the Apache Software License as +// published by the Apache Software Foundation; either version 1.1 +// of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// Apache Software Foundation Licens for more details. +// +// You may view the full text here: http://www.apache.org/LICENSE.txt + +package servletunit.struts.tests.cactus; + +import servletunit.struts.CactusStrutsTestCase; + +public class TestMessageResourceAction extends CactusStrutsTestCase { + + public TestMessageResourceAction(String testName) { + super(testName); + } + + public void setUp() throws Exception { + super.setUp(); + // todo: still needed for Struts 1.0 for some reason. + setInitParameter("application","examples.ApplicationResources"); + } + + public void testGetResources() { + + setRequestPathInfo("test","/testMessage"); + actionPerform(); + verifyForward("success"); + verifyNoActionErrors(); + } + + +} + Index: 3rdParty_sources/strutstest/servletunit/struts/tests/cactus/TestMultipleActions.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/strutstest/servletunit/struts/tests/cactus/Attic/TestMultipleActions.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/strutstest/servletunit/struts/tests/cactus/TestMultipleActions.java 17 Aug 2012 15:17:08 -0000 1.1 @@ -0,0 +1,48 @@ +// StrutsTestCase - a JUnit extension for testing Struts actions +// within the context of the ActionServlet. +// Copyright (C) 2002 Deryl Seale +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the Apache Software License as +// published by the Apache Software Foundation; either version 1.1 +// of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// Apache Software Foundation Licens for more details. +// +// You may view the full text here: http://www.apache.org/LICENSE.txt + +package servletunit.struts.tests.cactus; + +import servletunit.struts.CactusStrutsTestCase; + +public class TestMultipleActions extends CactusStrutsTestCase { + + public TestMultipleActions(String testName) { + super(testName); + } + + public void testMultipleActions() { + + addRequestParameter("username","deryl"); + addRequestParameter("password","radar"); + setRequestPathInfo("/login"); + actionPerform(); + verifyForward("success"); + verifyForwardPath("/main/success.jsp"); + assertEquals("deryl",getSession().getAttribute("authentication")); + verifyNoActionErrors(); + setRequestPathInfo("/testContextParams"); + actionPerform(); + verifyNoActionErrors(); + } + + public static void main(String[] args) { + junit.textui.TestRunner.run(TestMultipleActions.class); + } + + +} + Index: 3rdParty_sources/strutstest/servletunit/struts/tests/cactus/TestNoRequestPathInfo.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/strutstest/servletunit/struts/tests/cactus/Attic/TestNoRequestPathInfo.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/strutstest/servletunit/struts/tests/cactus/TestNoRequestPathInfo.java 17 Aug 2012 15:17:07 -0000 1.1 @@ -0,0 +1,31 @@ +package servletunit.struts.tests.cactus; + +import servletunit.struts.CactusStrutsTestCase; + +// StrutsTestCase - a JUnit extension for testing Struts actions +// within the context of the ActionServlet. +// Copyright (C) 2002 Deryl Seale +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the Apache Software License as +// published by the Apache Software Foundation; either version 1.1 +// of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// Apache Software Foundation Licens for more details. +// +// You may view the full text here: http://www.apache.org/LICENSE.txt +public class TestNoRequestPathInfo extends CactusStrutsTestCase { + + public void testNoPathSet() { + try { + actionPerform(); + fail("Should have thrown IllegalStateException"); + } catch (IllegalStateException ise) { + return; + } + } + +} Index: 3rdParty_sources/strutstest/servletunit/struts/tests/cactus/TestNullAction.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/strutstest/servletunit/struts/tests/cactus/Attic/TestNullAction.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/strutstest/servletunit/struts/tests/cactus/TestNullAction.java 17 Aug 2012 15:17:07 -0000 1.1 @@ -0,0 +1,28 @@ +package servletunit.struts.tests.cactus; + +import servletunit.struts.CactusStrutsTestCase; + +/** + * Created by IntelliJ IDEA. + * User: deryl + * Date: Apr 13, 2003 + * Time: 12:07:32 PM + * To change this template use Options | File Templates. + */ +public class TestNullAction extends CactusStrutsTestCase { + + public TestNullAction(String testName) { + super(testName); + } + + public void setUp() throws Exception { + super.setUp(); + } + + public void testNullAction() { + setRequestPathInfo("test","/testNullAction.do"); + actionPerform(); + verifyForward(null); + verifyForwardPath(null); + } +} Index: 3rdParty_sources/strutstest/servletunit/struts/tests/cactus/TestNullPointerAction.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/strutstest/servletunit/struts/tests/cactus/Attic/TestNullPointerAction.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/strutstest/servletunit/struts/tests/cactus/TestNullPointerAction.java 17 Aug 2012 15:17:07 -0000 1.1 @@ -0,0 +1,66 @@ +// StrutsTestCase - a JUnit extension for testing Struts actions +// within the context of the ActionServlet. +// Copyright (C) 2002 Deryl Seale +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the Apache Software License as +// published by the Apache Software Foundation; either version 1.1 +// of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// Apache Software Foundation Licens for more details. +// +// You may view the full text here: http://www.apache.org/LICENSE.txt +package servletunit.struts.tests.cactus; + +import servletunit.struts.*; + +/** + *

Title: NullPointerActionTest

+ *

Description: Tests to confirm a NullPointerException + * thrown from a misbehaving action reaches the test.

+ *

Copyright: Copyright (c) 2003

+ * @author Sean Pritchard + * @version 1.0 + */ +public class TestNullPointerAction extends CactusStrutsTestCase { + + public TestNullPointerAction() { + } + + public void setUp() throws Exception { + super.setUp(); + } + + public void testNullPointer() throws Exception{ + try{ + this.setRequestPathInfo("test","/testNullPointer"); + this.actionPerform(); + fail("Exception expected"); + }catch(ExceptionDuringTestError e){ + //uncomment this to see a sample stack trace + //that users will see if their action throws an exception +// throw e; + } + } + + public void testNullPointerFromForm() throws Exception{ + try{ + this.setRequestPathInfo("test","/testNullPointerForm"); + this.actionPerform(); + fail("Exception expected"); + }catch(ExceptionDuringTestError e){ + //uncomment this to see a sample stack trace + //that users will see if their action throws an exception +// throw e; + } + } + + + public static void main(String[] args) { + junit.textui.TestRunner.run(TestNullPointerAction.class); + } + +} \ No newline at end of file Index: 3rdParty_sources/strutstest/servletunit/struts/tests/cactus/TestProcessResults.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/strutstest/servletunit/struts/tests/cactus/Attic/TestProcessResults.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/strutstest/servletunit/struts/tests/cactus/TestProcessResults.java 17 Aug 2012 15:17:07 -0000 1.1 @@ -0,0 +1,33 @@ +package servletunit.struts.tests.cactus; + +import servletunit.struts.CactusStrutsTestCase; +import org.apache.cactus.WebResponse; + +public class TestProcessResults extends CactusStrutsTestCase { + + public void testSuccessfulLogin() { + processRequest(true); + addRequestParameter("username","deryl"); + addRequestParameter("password","radar"); + setRequestPathInfo("/login"); + actionPerform(); + verifyForward("success"); + verifyForwardPath("/main/success.jsp"); + assertEquals("deryl", getSession().getAttribute("authentication")); + verifyNoActionErrors(); + } + + public void endSuccessfulLogin(WebResponse response) { + assertEquals("unexpected response code",200,response.getStatusCode()); + String[] text = response.getTextAsArray(); + for (int i = 0; i < text.length; i++) { + String line = text[i]; + if (line != null && + !line.equals("

You have successfully logged in!

") && + !line.equals("Go back") && + !line.equals("")) + fail("unexpected text: " + line); + + } + } +} Index: 3rdParty_sources/strutstest/servletunit/struts/tests/cactus/TestRedirectAction.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/strutstest/servletunit/struts/tests/cactus/Attic/TestRedirectAction.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/strutstest/servletunit/struts/tests/cactus/TestRedirectAction.java 17 Aug 2012 15:17:08 -0000 1.1 @@ -0,0 +1,47 @@ +// StrutsTestCase - a JUnit extension for testing Struts actions +// within the context of the ActionServlet. +// Copyright (C) 2002 Deryl Seale +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the Apache Software License as +// published by the Apache Software Foundation; either version 1.1 +// of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// Apache Software Foundation Licens for more details. +// +// You may view the full text here: http://www.apache.org/LICENSE.txt + +package servletunit.struts.tests.cactus; + +import servletunit.struts.CactusStrutsTestCase; + +public class TestRedirectAction extends CactusStrutsTestCase { + + public TestRedirectAction(String testName) { + super(testName); + } + + public void testRedirect() { + setRequestPathInfo("test","/testRedirect"); + actionPerform(); + verifyForward("redirect"); + verifyForwardPath("/test/main/success.jsp"); + verifyNoActionErrors(); + } + + /** + * Confirms verifyForward works correctly when the redirect path + * is a relative (not absolute) URL + */ + public void testRelativeRedirect() { + setRequestPathInfo("test","/testRelativeRedirect"); + actionPerform(); + // in a servlet engine, this will have the context prepended + verifyForwardPath("/test/main/success.jsp"); + verifyNoActionErrors(); + } + +} Index: 3rdParty_sources/strutstest/servletunit/struts/tests/cactus/TestSetActionForm.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/strutstest/servletunit/struts/tests/cactus/Attic/TestSetActionForm.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/strutstest/servletunit/struts/tests/cactus/TestSetActionForm.java 17 Aug 2012 15:17:07 -0000 1.1 @@ -0,0 +1,87 @@ +// StrutsTestCase - a JUnit extension for testing Struts actions +// within the context of the ActionServlet. +// Copyright (C) 2002 Deryl Seale +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the Apache Software License as +// published by the Apache Software Foundation; either version 1.1 +// of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// Apache Software Foundation Licens for more details. +// +// You may view the full text here: http://www.apache.org/LICENSE.txt + +package servletunit.struts.tests.cactus; + +import servletunit.struts.CactusStrutsTestCase; +import servletunit.struts.tests.ComplexForm; +import examples.LoginForm; + +public class TestSetActionForm extends CactusStrutsTestCase { + + public TestSetActionForm(String testName) { + super(testName); + } + + public void testNonModuleSetActionForm() { + LoginForm form = new LoginForm(); + form.setUsername("deryl"); + form.setPassword("radar"); + setRequestPathInfo("/login"); + setActionForm(form); + actionPerform(); + verifyNoActionErrors(); + verifyForward("success"); + verifyForwardPath("/main/success.jsp"); + } + + public void testSetActionForm() { + ComplexForm form = new ComplexForm(); + form.setUsername("deryl"); + form.setPassword("radar"); + form.setComplexObject(new Object()); + setRequestPathInfo("test","/testSetActionForm"); + setActionForm(form); + actionPerform(); + verifyForward("success"); + verifyForwardPath("/test/main/success.jsp"); + verifyNoActionErrors(); + } + + public void testFormReset() { + ComplexForm form = new ComplexForm(); + form.setUsername("deryl"); + form.setPassword("radar"); + form.setComplexObject(new Object()); + setRequestPathInfo("test","/testSetActionForm"); + addRequestParameter("test.reset","true"); + setActionForm(form); + actionPerform(); + verifyForward("login"); + verifyForwardPath("/login/login.jsp"); + verifyActionErrors(new String[] {"error.password.mismatch"}); + } + + public void testSetActionFormBeforeSettingRequestPathFails() { + ComplexForm form = new ComplexForm(); + form.setUsername("deryl"); + form.setPassword("radar"); + form.setComplexObject(new Object()); + try { + setActionForm(form); + } catch (IllegalStateException ise) { + return; + } + fail("should have thrown IllegalStateException"); + } + + public static void main(String[] args) { + junit.textui.TestRunner.run(TestSetActionForm.class); + } + + +} + Index: 3rdParty_sources/strutstest/servletunit/struts/tests/cactus/TestSimpleForward.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/strutstest/servletunit/struts/tests/cactus/Attic/TestSimpleForward.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/strutstest/servletunit/struts/tests/cactus/TestSimpleForward.java 17 Aug 2012 15:17:08 -0000 1.1 @@ -0,0 +1,38 @@ +// StrutsTestCase - a JUnit extension for testing Struts actions +// within the context of the ActionServlet. +// Copyright (C) 2002 Deryl Seale +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the Apache Software License as +// published by the Apache Software Foundation; either version 1.1 +// of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// Apache Software Foundation Licens for more details. +// +// You may view the full text here: http://www.apache.org/LICENSE.txt + +package servletunit.struts.tests.cactus; + +import junit.framework.AssertionFailedError; +import servletunit.struts.CactusStrutsTestCase; + +public class TestSimpleForward extends CactusStrutsTestCase { + + public TestSimpleForward(String testName) { + super(testName); + } + + public void testSimpleForward() { + try { + setRequestPathInfo("test","/testSimpleForward"); + actionPerform(); + } catch (Exception e) { + e.printStackTrace(); + throw new AssertionFailedError("caught exception " + e.getClass() + " : " + e.getMessage()); + } + } + +} Index: 3rdParty_sources/strutstest/servletunit/struts/tests/cactus/TestTilesForward.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/strutstest/servletunit/struts/tests/cactus/Attic/TestTilesForward.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/strutstest/servletunit/struts/tests/cactus/TestTilesForward.java 17 Aug 2012 15:17:07 -0000 1.1 @@ -0,0 +1,79 @@ +// StrutsTestCase - a JUnit extension for testing Struts actions +// within the context of the ActionServlet. +// Copyright (C) 2002 Deryl Seale +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the Apache Software License as +// published by the Apache Software Foundation; either version 1.1 +// of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// Apache Software Foundation Licens for more details. +// +// You may view the full text here: http://www.apache.org/LICENSE.txt + +package servletunit.struts.tests.cactus; + +import servletunit.struts.CactusStrutsTestCase; +import junit.framework.AssertionFailedError; + +public class TestTilesForward extends CactusStrutsTestCase { + + public TestTilesForward(String testName) { + super(testName); + } + + public void setUp() throws Exception { + super.setUp(); + } + + public void testTilesForward() { + addRequestParameter("username","deryl"); + addRequestParameter("password","radar"); + setRequestPathInfo("tiles","/tilesForward"); + actionPerform(); + verifyForward("success"); + verifyForwardPath("/layouts/pageLayout.jsp"); + verifyTilesForward("success","page.library"); + } + + public void testTilesInputForward() { + setRequestPathInfo("tiles","/tilesInputForward.do"); + actionPerform(); + verifyInputForward(); + } + + public void testTileForwardFail() { + addRequestParameter("username","deryl"); + addRequestParameter("password","radar"); + setRequestPathInfo("tiles","/tilesForward.do"); + actionPerform(); + verifyForward("success"); + verifyForwardPath("/layouts/pageLayout.jsp"); + try { + verifyTilesForward("success","foo.fail"); + } catch (AssertionFailedError afe) { + return; + } + fail("Should have failed."); + } + +// public void testTileForwardFailDefinitionExists() { +// addRequestParameter("username","deryl"); +// addRequestParameter("password","radar"); +// setRequestPathInfo("tiles","/tilesForward.do"); +// actionPerform(); +// verifyForward("success"); +// verifyForwardPath("/layouts/pageLayout.jsp"); +// try { +// verifyTilesForward("failure","another.page"); +// } catch (AssertionFailedError afe) { +// return; +// } +// fail("Should have failed."); +// } + + +} Index: 3rdParty_sources/strutstest/servletunit/struts/tests/cactus/TestTokenAction.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/strutstest/servletunit/struts/tests/cactus/Attic/TestTokenAction.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/strutstest/servletunit/struts/tests/cactus/TestTokenAction.java 17 Aug 2012 15:17:08 -0000 1.1 @@ -0,0 +1,39 @@ +// StrutsTestCase - a JUnit extension for testing Struts actions +// within the context of the ActionServlet. +// Copyright (C) 2002 Deryl Seale +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the Apache Software License as +// published by the Apache Software Foundation; either version 1.1 +// of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// Apache Software Foundation Licens for more details. +// +// You may view the full text here: http://www.apache.org/LICENSE.txt + +package servletunit.struts.tests.cactus; + +import org.apache.struts.action.Action; +import org.apache.struts.taglib.html.Constants; +import org.apache.struts.Globals; +import servletunit.struts.CactusStrutsTestCase; + +public class TestTokenAction extends CactusStrutsTestCase { + + public TestTokenAction(String testName) { + super(testName); + } + + public void testTransactionToken() { + addRequestParameter(Constants.TOKEN_KEY, "test_token"); + getSession().setAttribute(Globals.TRANSACTION_TOKEN_KEY, "test_token"); + setRequestPathInfo("test","/testToken"); + actionPerform(); + verifyNoActionErrors(); + } + + +} Index: 3rdParty_sources/strutstest/servletunit/struts/tests/cactus/TestUserAction.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/strutstest/servletunit/struts/tests/cactus/Attic/TestUserAction.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/strutstest/servletunit/struts/tests/cactus/TestUserAction.java 17 Aug 2012 15:17:07 -0000 1.1 @@ -0,0 +1,37 @@ +// StrutsTestCase - a JUnit extension for testing Struts actions +// within the context of the ActionServlet. +// Copyright (C) 2002 Deryl Seale +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the Apache Software License as +// published by the Apache Software Foundation; either version 1.1 +// of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// Apache Software Foundation Licens for more details. +// +// You may view the full text here: http://www.apache.org/LICENSE.txt + +package servletunit.struts.tests.cactus; + +import servletunit.struts.CactusStrutsTestCase; + +/** + * This class is reserved for quickly testing out other + * user's actions, to help in debugging their problems. + * It is deliberately checked in empty, as it is a place- + * holder. + */ +public class TestUserAction extends CactusStrutsTestCase { + + public TestUserAction(String testName) { + super(testName); + } + + public void testAction() { + } + + +} Index: 3rdParty_sources/strutstest/servletunit/tests/TestCookies.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/strutstest/servletunit/tests/Attic/TestCookies.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/strutstest/servletunit/tests/TestCookies.java 17 Aug 2012 15:17:08 -0000 1.1 @@ -0,0 +1,83 @@ +// StrutsTestCase - a JUnit extension for testing Struts actions +// within the context of the ActionServlet. +// Copyright (C) 2002 Deryl Seale +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the Apache Software License as +// published by the Apache Software Foundation; either version 1.1 +// of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// Apache Software Foundation Licens for more details. +// +// You may view the full text here: http://www.apache.org/LICENSE.txt + +package servletunit.tests; + +import junit.framework.TestCase; +import servletunit.HttpServletRequestSimulator; + +import javax.servlet.http.Cookie; + +public class TestCookies extends TestCase { + + HttpServletRequestSimulator request; + + public TestCookies(String testName) { + super(testName); + } + + public void setUp() { + this.request = new HttpServletRequestSimulator(null); + } + + public void testNoCookies() { + assertNull(request.getCookies()); + } + + public void testAddCookie() { + request.addCookie(new Cookie("test","testValue")); + Cookie[] cookies = request.getCookies(); + boolean assertion = false; + for (int i = 0; i < cookies.length; i++) { + if ((cookies[i].getName().equals("test")) && (cookies[i].getValue().equals("testValue"))) + assertion = true; + } + assertTrue(assertion); + } + + public void testSetCookies() { + Cookie[] cookies = new Cookie[2]; + cookies[0] = new Cookie("test","testValue"); + cookies[1] = new Cookie("test2","testValue2"); + boolean assert1 = false; + boolean assert2 = false; + request.setCookies(cookies); + Cookie[] resultCookies = request.getCookies(); + for (int i = 0; i < resultCookies.length; i++) { + if ((resultCookies[i].getName().equals("test")) && (resultCookies[i].getValue().equals("testValue"))) + assert1 = true; + if ((resultCookies[i].getName().equals("test2")) && (resultCookies[i].getValue().equals("testValue2"))) + assert2 = true; + + } + assertTrue(assert1 && assert2); + } + + public void testCheckForWrongCookie() { + request.addCookie(new Cookie("test","testValue")); + Cookie[] cookies = request.getCookies(); + boolean assertion = true; + for (int i = 0; i < cookies.length; i++) { + if ((cookies[i].getName().equals("badValue")) && (cookies[i].getValue().equals("dummyValue"))) + assertion = false; + } + assertTrue(assertion); + } + + + + +} Index: 3rdParty_sources/strutstest/servletunit/tests/TestHttpServletRequestSimulator.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/strutstest/servletunit/tests/Attic/TestHttpServletRequestSimulator.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/strutstest/servletunit/tests/TestHttpServletRequestSimulator.java 17 Aug 2012 15:17:08 -0000 1.1 @@ -0,0 +1,193 @@ +// StrutsTestCase - a JUnit extension for testing Struts actions +// within the context of the ActionServlet. +// Copyright (C) 2002 Deryl Seale +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the Apache Software License as +// published by the Apache Software Foundation; either version 1.1 +// of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// Apache Software Foundation Licens for more details. +// +// You may view the full text here: http://www.apache.org/LICENSE.txt + +package servletunit.tests; + +import junit.framework.TestCase; +import servletunit.HttpServletRequestSimulator; +import servletunit.ServletContextSimulator; + +import javax.servlet.RequestDispatcher; +import java.io.File; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Enumeration; +import java.util.Locale; +import java.util.Date; + +/** + * A Junit based test of the HttpServletResponseSimulator class + * @author Sean Pritchard + * @version 1.0 + */ + +public class TestHttpServletRequestSimulator extends TestCase { + + HttpServletRequestSimulator request; + ServletContextSimulator context; + + public TestHttpServletRequestSimulator(String testCase) { + super(testCase); + } + + public void setUp() { + context = new ServletContextSimulator(); + request = new HttpServletRequestSimulator(context); + } + + public void testAddParameterArray() { + String[] values = { "value1", "value2" }; + request.addParameter("name1",values); + String[] result = request.getParameterValues("name1"); + if (result.length != 2) + fail(); + if (!((result[0].equals("value1")) && (result[1].equals("value2")))) + fail(); + } + + public void testGetParameterValuesSingle() { + request.addParameter("name1","value1"); + String[] result = request.getParameterValues("name1"); + if (result.length != 1) + fail(); + if (!(result[0].equals("value1"))) + fail(); + } + + public void testGetParameterWithNullKey() { + String result = request.getParameter(null); + assertNull(result); + + } + + public void testGetParameterValuesWithNullKey() { + String[] result = request.getParameterValues(null); + assertNull(result); + + } + + public void testGetParameterWithArray() { + String[] values = { "value1", "value2" }; + request.addParameter("name1",values); + String result = request.getParameter("name1"); + if (!(result.equals("value1"))) + fail(); + } + + public void testSetAttributeNullValue() { + request.setAttribute("test1","value1"); + assertEquals(request.getAttribute("test1"),"value1"); + request.setAttribute("test1",null); + assertNull(request.getAttribute("test1")); + } + + public void testSetAttribute() { + request.setAttribute("test1","value1"); + assertEquals(request.getAttribute("test1"),"value1"); + } + + public void testIsUserInRole() { + request.setUserRole("role1"); + assertTrue(request.isUserInRole("role1")); + } + + public void testIsUserInRoleFalse() { + request.setUserRole("role2"); + assertTrue(!request.isUserInRole("role1")); + } + + public void testGetServerPort() { + request.setServerPort(8080); + assertEquals(request.getServerPort(),8080); + } + + public void testGetRequestURLWithQueryString() { + request.setRequestURL("https://server:8080/my/request/url?param=1"); + assertEquals("https://server:8080/my/request/url",request.getRequestURL().toString()); + assertEquals("param=1",request.getQueryString()); + assertEquals("https",request.getScheme()); + assertTrue(request.isSecure()); + assertEquals("/my/request/url",request.getRequestURI()); + assertEquals("server",request.getServerName()); + assertEquals(8080,request.getServerPort()); + } + + public void testGetRequestURLWithoutQueryStringOrPort() { + request.setRequestURL("http://server/my/request/url"); + assertEquals("http://server/my/request/url",request.getRequestURL().toString()); + assertNull(request.getQueryString()); + assertEquals("http",request.getScheme()); + assertTrue(!request.isSecure()); + assertEquals("/my/request/url",request.getRequestURI()); + assertEquals("server",request.getServerName()); + assertEquals(80,request.getServerPort()); + } + + public void testGetSecurePort() { + request.setRequestURL("https://server/my/request/url?param=1"); + assertTrue(request.isSecure()); + assertEquals(443,request.getServerPort()); + } + + public void testGetLocales() { + Enumeration enum = request.getLocales(); + for (Object enumObject = enum.nextElement(); enum.hasMoreElements(); enumObject = enum.nextElement()) { + Locale locale = (Locale) enumObject; + if (!locale.equals(Locale.US)) + fail(); + } + } + + public void testGetDateHeaderNoHeader() { + assertEquals(-1,request.getDateHeader("foo")); + } + + public void testGetDateHeaderBadHeader() { + request.setHeader("DATE_HEADER","foofoofoo"); + try { + request.getDateHeader("DATE_HEADER"); + } catch (IllegalArgumentException iae) { + return; + } + fail(); + } + + public void testGetDateHeader() throws ParseException + { + String date = "05/23/73 8:05 PM, PST"; + long time = new SimpleDateFormat().parse(date).getTime(); + request.setDateHeader("DATE_HEADER",time); + assertEquals(time,request.getDateHeader("DATE_HEADER")); + } + + public void testGetRealPath() { + File file = new File(System.getProperty("basedir")); + context.setContextDirectory(file); + assertEquals(new File(file,"test.html").getAbsolutePath(),request.getRealPath("/test.html")); + } + + public void testGetRealPathNotSet() { + assertNull(request.getRealPath("/test.html")); + } + + public void testReturnsRequestDispatcher() { + RequestDispatcher dispatcher = request.getRequestDispatcher("/test/login.jsp"); + assertNotNull(dispatcher); + } + + +} + Index: 3rdParty_sources/strutstest/servletunit/tests/TestHttpServletResponseSimulator.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/strutstest/servletunit/tests/Attic/TestHttpServletResponseSimulator.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/strutstest/servletunit/tests/TestHttpServletResponseSimulator.java 17 Aug 2012 15:17:08 -0000 1.1 @@ -0,0 +1,155 @@ +// StrutsTestCase - a JUnit extension for testing Struts actions +// within the context of the ActionServlet. +// Copyright (C) 2002 Deryl Seale +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the Apache Software License as +// published by the Apache Software Foundation; either version 1.1 +// of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// Apache Software Foundation Licens for more details. +// +// You may view the full text here: http://www.apache.org/LICENSE.txt + +package servletunit.tests; + +import junit.framework.Test; +import junit.framework.TestCase; +import junit.framework.TestSuite; +import servletunit.HttpServletResponseSimulator; + +import java.util.Date; + +/** + * A Junit based test of the HttpServletResponseSimulator class + * @author Sean Pritchard + * @version 1.0 + */ + +public class TestHttpServletResponseSimulator extends TestCase { + + public TestHttpServletResponseSimulator(String testCase) { + super(testCase); + } + + /** + * Ensures the value returned by encodeURL contains the + * original url. + */ + public void testEncodeURL(){ + HttpServletResponseSimulator response = new HttpServletResponseSimulator(); + String url = "http://sourceforge.net"; + assertTrue(response.encodeURL(url).indexOf(url)!=-1); + } + + /** + * Ensures the value returned by encodeUrl contains the + * original url. + */ + public void testEncodeUrl(){ + HttpServletResponseSimulator response = new HttpServletResponseSimulator(); + String url = "http://sourceforge.net"; + assertTrue(response.encodeUrl(url).indexOf(url)!=-1); + } + + /** + * Ensures the value returned by encodeRedirectURL contains the + * original url. + */ + public void testEncodeRedirectURL(){ + HttpServletResponseSimulator response = new HttpServletResponseSimulator(); + String url = "http://sourceforge.net"; + assertTrue(response.encodeRedirectURL(url).indexOf(url)!=-1); + } + + /** + * Ensures the value returned by encodeRedirectUrl contains the + * original url. + */ + public void testEncodeRedirectUrl(){ + HttpServletResponseSimulator response = new HttpServletResponseSimulator(); + String url = "http://sourceforge.net"; + assertTrue(response.encodeRedirectUrl(url).indexOf(url)!=-1); + } + + /** + * tests the setHeader() and containsHeader() methods + */ + public void testSetHeader() { + HttpServletResponseSimulator response = new HttpServletResponseSimulator(); + response.setHeader("TestName", "testValue"); + assertTrue(response.containsHeader("TestName")); + } + + /** + * tests the setIntHeader() and containsHeader() methods. + */ + public void testSetIntHeader() { + HttpServletResponseSimulator response = new HttpServletResponseSimulator(); + response.setIntHeader("TestName", 5); + assertTrue(response.containsHeader("TestName")); + } + + + public static Test suite() { + return new TestSuite(TestHttpServletResponseSimulator.class); + } + + /** + * tests the send redirect method + * @throws Exception + */ + public void testSendRedirect() throws Exception{ + HttpServletResponseSimulator response = new HttpServletResponseSimulator(); + response.sendRedirect("http://sourceforge.net"); + response.containsHeader("Location"); + } + + /** + * tests that getContentType() returns the value previously set + * by calling setContentType() or setHeader() with a "Content-type" + * parameter + */ + public void testContentType(){ + String type = "image/gif"; + String type2 = "text/xml"; + String type3 = "video/mpeg"; + HttpServletResponseSimulator response = new HttpServletResponseSimulator(); + response.setContentType(type); + assertEquals(type, response.getContentType()); + response.setHeader("Content-type", type2); + assertEquals(type2, response.getContentType()); + response.addHeader("Content-type", type3); + assertEquals(type3, response.getContentType()); + } + + /** + * tests that getContentLength() returns the value previously set + * by calling setContentLength() or setIntHeader() with a "Content-length" + * parameter + */ + public void testContentLength(){ + int len1 = 25; + int len2 = 156; + int len3 = 42; + HttpServletResponseSimulator response = new HttpServletResponseSimulator(); + response.setContentLength(len1); + assertEquals(len1, response.getContentLength()); + response.setIntHeader("Content-length", len2); + assertEquals(len2, response.getContentLength()); + response.addIntHeader("Content-length", len3); + assertEquals(len3, response.getContentLength()); + } + + + public void testAddDateHeader() { + Date date = new Date(2004,5,23); + HttpServletResponseSimulator response = new HttpServletResponseSimulator(); + response.addDateHeader("date",date.getTime()); + assertEquals("unexpected header value","Thu, 23 Jun 3904 00:00:00 PDT",response.getHeader("date")); + } +} + Index: 3rdParty_sources/strutstest/servletunit/tests/TestInitParameters.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/strutstest/servletunit/tests/Attic/TestInitParameters.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/strutstest/servletunit/tests/TestInitParameters.java 17 Aug 2012 15:17:08 -0000 1.1 @@ -0,0 +1,64 @@ +// StrutsTestCase - a JUnit extension for testing Struts actions +// within the context of the ActionServlet. +// Copyright (C) 2002 Deryl Seale +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the Apache Software License as +// published by the Apache Software Foundation; either version 1.1 +// of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// Apache Software Foundation Licens for more details. +// +// You may view the full text here: http://www.apache.org/LICENSE.txt + +package servletunit.tests; + +import junit.framework.TestCase; +import servletunit.ServletConfigSimulator; + +import java.util.Enumeration; + +public class TestInitParameters extends TestCase { + + ServletConfigSimulator config; + + public TestInitParameters(String testName) { + super(testName); + } + + public void setUp() { + config = new ServletConfigSimulator(); + } + + public void testSetInitParameter() { + config.setInitParameter("test","testValue"); + assertEquals("testValue",config.getInitParameter("test")); + } + + public void testNoParameter() { + assertNull(config.getInitParameter("badValue")); + } + + public void testGetInitParameterNames() { + config.setInitParameter("test","testValue"); + config.setInitParameter("another","anotherValue"); + assertEquals("testValue",config.getInitParameter("test")); + assertEquals("anotherValue",config.getInitParameter("another")); + Enumeration names = config.getInitParameterNames(); + boolean fail = true; + while (names.hasMoreElements()) { + fail = true; + String name = (String) names.nextElement(); + if ((name.equals("test")) || (name.equals("another"))) + fail = false; + } + if (fail) + fail(); + } + +} + + Index: 3rdParty_sources/strutstest/servletunit/tests/TestServletContext.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/strutstest/servletunit/tests/Attic/TestServletContext.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/strutstest/servletunit/tests/TestServletContext.java 17 Aug 2012 15:17:08 -0000 1.1 @@ -0,0 +1,183 @@ +// StrutsTestCase - a JUnit extension for testing Struts actions +// within the context of the ActionServlet. +// Copyright (C) 2002 Deryl Seale +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the Apache Software License as +// published by the Apache Software Foundation; either version 1.1 +// of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// Apache Software Foundation Licens for more details. +// +// You may view the full text here: http://www.apache.org/LICENSE.txt + +package servletunit.tests; + +import junit.framework.TestCase; +import servletunit.ServletContextSimulator; + +import java.util.Enumeration; +import java.io.File; + +public class TestServletContext extends TestCase { + + String contextDirectory = "src/examples"; + ServletContextSimulator context; + + public TestServletContext(String testName) { + super(testName); + } + + public void setUp() { + context = new ServletContextSimulator(); + } + + public void testSetAttribute() { + context.setAttribute("test","testValue"); + assertEquals("testValue",context.getAttribute("test")); + } + + public void testNoAttribute() { + assertNull(context.getAttribute("badValue")); + } + + public void testGetAttributeNames() { + context.setAttribute("test","testValue"); + context.setAttribute("another","anotherValue"); + assertEquals("testValue",context.getAttribute("test")); + assertEquals("anotherValue",context.getAttribute("another")); + Enumeration names = context.getAttributeNames(); + boolean fail = true; + while (names.hasMoreElements()) { + fail = true; + String name = (String) names.nextElement(); + if ((name.equals("test")) || (name.equals("another"))) + fail = false; + } + if (fail) + fail(); + } + + public void testGetRealPath() { + File file = new File(System.getProperty("basedir")); + context.setContextDirectory(file); + assertEquals(new File(file,"test.html").getAbsolutePath(),context.getRealPath("/test.html")); + } + + public void testGetRealPathNotSet() { + context.setContextDirectory(null); + assertNull(context.getRealPath("/test.html")); + } + + /** + * verifies that web.xml can be loaded + * using the classpath + */ + public void testGetResourceAsStreamFromClasspath(){ + assertNotNull("resource was not found", context.getResourceAsStream("/WEB-INF/web.xml")); + } + + /** + * verified that web.xml can be loaded as a URL using the classpath + * @throws Exception + */ + public void testGetResourceFromClasspath() throws Exception{ + assertNotNull("resource was not found", context.getResource("/WEB-INF/web.xml")); + } + + /** + * verifies that web.xml can be loaded + * using the filesystem. Assumes test is being run from + * the strutstestcase project root directory + * and that WEB-INF is in src/examples + */ + public void testGetResourceAsStreamFromFileSystem(){ + context.setContextDirectory(new File(contextDirectory)); + assertNotNull("resource was not found", context.getResourceAsStream("/WEB-INF/web.xml")); + } + + /** + * verified that web.xml can be loaded as a URL using the classpath + * @throws Exception + */ + public void testGetResourceFromFileSystem() throws Exception{ + context.setContextDirectory(new File(contextDirectory)); + assertNotNull("resource was not found", context.getResource("/WEB-INF/web.xml")); + } + + /** + * confirms that calls to getResource will + * adjust to a path missing the leading "/" + * @throws Exception + */ + public void testGetResourceFromFileSystemWithPathCorrection() throws Exception{ + context.setContextDirectory(new File(contextDirectory)); + assertNotNull("resource was not found", context.getResource("WEB-INF/web.xml")); + } + + /** + * confirms that calls to getResource will + * adjust to a path missing the leading "/" + * @throws Exception + */ + public void testGetResourceFromClasspathWithPathCorrection() throws Exception{ + assertNotNull("resource was not found", context.getResource("WEB-INF/web.xml")); + } + + /** + * confirms that calls to getResource will + * adjust to a path missing the leading "/" + * @throws Exception + */ + public void testGetResourceAsStreamFromFileSystemWithPathCorrection() throws Exception{ + context.setContextDirectory(new File(contextDirectory)); + assertNotNull("resource was not found", context.getResourceAsStream("WEB-INF/web.xml")); + } + + /** + * confirms that calls to getResource will + * adjust to a path missing the leading "/" + * @throws Exception + */ + public void testGetResourceAsStreamFromClasspathWithPathCorrection() throws Exception{ + assertNotNull("resource was not found", context.getResourceAsStream("WEB-INF/web.xml")); + } + + /** + * verifies that web.xml can be loaded + * using the filesystem. Assumes test is being run from + * the strutstestcase project root directory + * and that WEB-INF is in src/examples + * this is necessary because the other tests could be "fooled" + * by a file that was actually loaded by the classloader. + */ + public void testGetResourceAsFileFromFileSystem(){ + context.setContextDirectory(new File(contextDirectory)); + File file = context.getResourceAsFile("/WEB-INF/web.xml"); + assertNotNull("resource was not found", file); + assertTrue("resource was not found", file.exists()); + } + + /** + * verifies that web.xml can be loaded + * using the filesystem. Assumes test is being run from + * the strutstestcase project root directory + * and that WEB-INF is in src/examples + * this is necessary because the other tests could be "fooled" + * by a file that was actually loaded by the classloader. + */ + public void testGetResourceAsFileFromFileSystemWithRelativePath(){ + File file = context.getResourceAsFile("/src/examples/WEB-INF/web.xml"); + assertNotNull("resource was not found", file); + assertTrue("resource was not found", file.exists()); + } + + + + + + +} Index: 3rdParty_sources/strutstest/servletunit/tests/TestSession.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/strutstest/servletunit/tests/Attic/TestSession.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/strutstest/servletunit/tests/TestSession.java 17 Aug 2012 15:17:08 -0000 1.1 @@ -0,0 +1,72 @@ +// StrutsTestCase - a JUnit extension for testing Struts actions +// within the context of the ActionServlet. +// Copyright (C) 2002 Deryl Seale +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the Apache Software License as +// published by the Apache Software Foundation; either version 1.1 +// of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// Apache Software Foundation Licens for more details. +// +// You may view the full text here: http://www.apache.org/LICENSE.txt + +package servletunit.tests; + +import junit.framework.TestCase; +import servletunit.HttpServletRequestSimulator; + +import javax.servlet.http.HttpSession; + +public class TestSession extends TestCase { + + HttpServletRequestSimulator request; + + public TestSession(String testName) { + super(testName); + } + + public void setUp() { + this.request = new HttpServletRequestSimulator(null); + } + + public void testGetSession() { + assertNotNull(request.getSession()); + } + + public void testGetSessionTrue() { + assertNotNull(request.getSession(true)); + } + + public void testGetSessionFalse() { + assertNull(request.getSession(false)); + } + + public void testGetSessionFalseSessionExists() { + request.getSession(); + assertNotNull(request.getSession(false)); + } + + public void testGetSessionInvalid() { + request.getSession().invalidate(); + assertNotNull(request.getSession(true)); + } + + public void testGetSessionInvalidFalse() { + request.getSession().invalidate(); + assertNull(request.getSession(false)); + } + + public void testSetAttributeNull() { + HttpSession session = request.getSession(); + session.setAttribute("test","test"); + assertEquals("test",session.getAttribute("test")); + session.setAttribute("test",null); + assertNull(session.getAttribute("test")); + } + + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/AbstractElementExtensibleXMLObject.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/AbstractElementExtensibleXMLObject.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/AbstractElementExtensibleXMLObject.java 17 Aug 2012 15:17:07 -0000 1.1 @@ -0,0 +1,64 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml; + +import java.util.Collections; +import java.util.List; + +import javax.xml.namespace.QName; + +import org.opensaml.xml.util.IndexedXMLObjectChildrenList; +import org.opensaml.xml.validation.AbstractValidatingXMLObject; + +/** + * AbstractElementExtensible is an element of type xs:any, but without xs:anyAttribute + * attribute or text content. + */ +public abstract class AbstractElementExtensibleXMLObject extends AbstractValidatingXMLObject implements + ElementExtensibleXMLObject { + + /** xs:any {@link XMLObject} child elements. */ + private IndexedXMLObjectChildrenList anyXMLObjects; + + /** + * Constructor. + * + * @param namespaceURI the namespace the element is in + * @param elementLocalName the local name of the XML element this Object represents + * @param namespacePrefix the prefix for the given namespace + */ + public AbstractElementExtensibleXMLObject(String namespaceURI, String elementLocalName, String namespacePrefix) { + super(namespaceURI, elementLocalName, namespacePrefix); + anyXMLObjects = new IndexedXMLObjectChildrenList(this); + } + + /** {@inheritDoc} */ + public List getOrderedChildren() { + return Collections.unmodifiableList(anyXMLObjects); + } + + /** {@inheritDoc} */ + public List getUnknownXMLObjects() { + return anyXMLObjects; + } + + /** {@inheritDoc} */ + public List getUnknownXMLObjects(QName typeOrName) { + return (List) anyXMLObjects.subList(typeOrName); + } +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/AbstractElementExtensibleXMLObjectMarshaller.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/AbstractElementExtensibleXMLObjectMarshaller.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/AbstractElementExtensibleXMLObjectMarshaller.java 17 Aug 2012 15:17:07 -0000 1.1 @@ -0,0 +1,64 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml; + +import org.opensaml.xml.io.AbstractXMLObjectMarshaller; +import org.opensaml.xml.io.MarshallingException; +import org.w3c.dom.Element; + +/** + * AbstractElementExtensibleMarshaller marshalls element of type xs:any, but without + * xs:anyAttribute attributes or text content. + */ +public abstract class AbstractElementExtensibleXMLObjectMarshaller extends AbstractXMLObjectMarshaller { + + /** Constructor. */ + public AbstractElementExtensibleXMLObjectMarshaller(){ + super(); + } + + /** + * Constructor. + * + * @deprecated no replacement + * + * @param targetNamespaceURI the namespace URI of either the schema type QName or element QName of the elements this + * unmarshaller operates on + * @param targetLocalName the local name of either the schema type QName or element QName of the elements this + * unmarshaller operates on + */ + protected AbstractElementExtensibleXMLObjectMarshaller(String targetNamespaceURI, String targetLocalName) { + super(targetNamespaceURI, targetLocalName); + } + + /** + * No xs:anyAttribute attributes. + * + * {@inheritDoc} + */ + protected void marshallAttributes(XMLObject xmlObject, Element domElement) throws MarshallingException { + } + + /** + * No text content. + * + * {@inheritDoc} + */ + protected void marshallElementContent(XMLObject xmlObject, Element domElement) throws MarshallingException { + } +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/AbstractElementExtensibleXMLObjectUnmarshaller.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/AbstractElementExtensibleXMLObjectUnmarshaller.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/AbstractElementExtensibleXMLObjectUnmarshaller.java 17 Aug 2012 15:17:07 -0000 1.1 @@ -0,0 +1,75 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml; + +import org.opensaml.xml.io.AbstractXMLObjectUnmarshaller; +import org.opensaml.xml.io.UnmarshallingException; +import org.w3c.dom.Attr; + +/** + * AbstractElementExtensibleUnmarshaller unmarshalls element of type xs:any, but without + * xs:anyAttribute attributes or text content. + */ +public abstract class AbstractElementExtensibleXMLObjectUnmarshaller extends AbstractXMLObjectUnmarshaller { + + /** Constructor. */ + public AbstractElementExtensibleXMLObjectUnmarshaller(){ + super(); + } + + /** + * Constructor. + * + * @deprecated no replacement + * + * @param targetNamespaceURI the namespace URI of either the schema type QName or element QName of the elements this + * unmarshaller operates on + * @param targetLocalName the local name of either the schema type QName or element QName of the elements this + * unmarshaller operates on + */ + public AbstractElementExtensibleXMLObjectUnmarshaller(String targetNamespaceURI, String targetLocalName) { + super(targetNamespaceURI, targetLocalName); + } + + /** + * Unmarshalls all child elements in the xs:any list. + * + * {@inheritDoc} + */ + protected void processChildElement(XMLObject parentXMLObject, XMLObject childXMLObject) + throws UnmarshallingException { + ElementExtensibleXMLObject any = (ElementExtensibleXMLObject) parentXMLObject; + any.getUnknownXMLObjects().add(childXMLObject); + } + + /** + * No xs:anyAttribute attribute. + * + * {@inheritDoc} + */ + protected void processAttribute(XMLObject xmlObject, Attr attribute) throws UnmarshallingException { + } + + /** + * No text content. + * + * {@inheritDoc} + */ + protected void processElementContent(XMLObject xmlObject, String elementContent) { + } +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/AbstractExtensibleXMLObject.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/AbstractExtensibleXMLObject.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/AbstractExtensibleXMLObject.java 17 Aug 2012 15:17:07 -0000 1.1 @@ -0,0 +1,48 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml; + +import org.opensaml.xml.util.AttributeMap; + +/** + * AbstractExtensibleXMLObject is an element of type xs:any, and with xs:anyAttribute + * attributes. + */ +public abstract class AbstractExtensibleXMLObject extends AbstractElementExtensibleXMLObject implements + AttributeExtensibleXMLObject, ElementExtensibleXMLObject { + + /** xs:anyAttribute for this element. */ + private AttributeMap anyAttributes; + + /** + * Constructor. + * + * @param namespaceURI the namespace the element is in + * @param elementLocalName the local name of the XML element this Object represents + * @param namespacePrefix the prefix for the given namespace + */ + public AbstractExtensibleXMLObject(String namespaceURI, String elementLocalName, String namespacePrefix) { + super(namespaceURI, elementLocalName, namespacePrefix); + anyAttributes = new AttributeMap(this); + } + + /** {@inheritDoc} */ + public AttributeMap getUnknownAttributes() { + return anyAttributes; + } +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/AbstractExtensibleXMLObjectMarshaller.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/AbstractExtensibleXMLObjectMarshaller.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/AbstractExtensibleXMLObjectMarshaller.java 17 Aug 2012 15:17:07 -0000 1.1 @@ -0,0 +1,75 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml; + +import java.util.Map.Entry; + +import javax.xml.namespace.QName; + +import org.opensaml.xml.io.MarshallingException; +import org.opensaml.xml.util.XMLHelper; +import org.w3c.dom.Attr; +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +/** + * AbstractExtensibleXMLObjectMarshaller marshalls element of type xs:any and with + * xs:anyAttribute attributes. + */ +public class AbstractExtensibleXMLObjectMarshaller extends AbstractElementExtensibleXMLObjectMarshaller { + + /** Constructor. */ + public AbstractExtensibleXMLObjectMarshaller(){ + super(); + } + + /** + * Constructor. + * + * @deprecated no replacement + * + * @param targetNamespaceURI the namespace URI of either the schema type QName or element QName of the elements this + * unmarshaller operates on + * @param targetLocalName the local name of either the schema type QName or element QName of the elements this + * unmarshaller operates on + */ + public AbstractExtensibleXMLObjectMarshaller(String targetNamespaceURI, String targetLocalName) { + super(targetNamespaceURI, targetLocalName); + } + + /** + * Marshalls the xs:anyAttribute attributes. + * + * {@inheritDoc} + */ + protected void marshallAttributes(XMLObject xmlObject, Element domElement) throws MarshallingException { + AttributeExtensibleXMLObject anyAttribute = (AttributeExtensibleXMLObject) xmlObject; + Attr attribute; + Document document = domElement.getOwnerDocument(); + for (Entry entry : anyAttribute.getUnknownAttributes().entrySet()) { + attribute = XMLHelper.constructAttribute(document, entry.getKey()); + attribute.setValue(entry.getValue()); + domElement.setAttributeNodeNS(attribute); + if (Configuration.isIDAttribute(entry.getKey()) + || anyAttribute.getUnknownAttributes().isIDAttribute(entry.getKey())) { + attribute.getOwnerElement().setIdAttributeNode(attribute, true); + } + } + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/AbstractExtensibleXMLObjectUnmarshaller.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/AbstractExtensibleXMLObjectUnmarshaller.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/AbstractExtensibleXMLObjectUnmarshaller.java 17 Aug 2012 15:17:07 -0000 1.1 @@ -0,0 +1,66 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml; + +import javax.xml.namespace.QName; + +import org.opensaml.xml.io.UnmarshallingException; +import org.opensaml.xml.util.XMLHelper; +import org.w3c.dom.Attr; + +/** + * AbstractExtensibleXMLObjectUnmarshaller unmarshalls element of type xs:any and with + * xs:anyAttribute attributes. + */ +public abstract class AbstractExtensibleXMLObjectUnmarshaller extends AbstractElementExtensibleXMLObjectUnmarshaller { + + /** Constructor. */ + public AbstractExtensibleXMLObjectUnmarshaller(){ + super(); + } + + /** + * Constructor. + * + * @deprecated no replacement + * + * @param targetNamespaceURI the namespace URI of either the schema type QName or element QName of the elements this + * unmarshaller operates on + * @param targetLocalName the local name of either the schema type QName or element QName of the elements this + * unmarshaller operates on + */ + public AbstractExtensibleXMLObjectUnmarshaller(String targetNamespaceURI, String targetLocalName) { + super(targetNamespaceURI, targetLocalName); + } + + /** + * Unmarshalls the xs:anyAttribute attributes. + * + * {@inheritDoc} + */ + protected void processAttribute(XMLObject xmlObject, Attr attribute) throws UnmarshallingException { + AttributeExtensibleXMLObject anyAttribute = (AttributeExtensibleXMLObject) xmlObject; + QName attribQName = XMLHelper.constructQName(attribute.getNamespaceURI(), attribute.getLocalName(), attribute + .getPrefix()); + if (attribute.isId()) { + anyAttribute.getUnknownAttributes().registerID(attribQName); + } + anyAttribute.getUnknownAttributes().put(attribQName, attribute.getValue()); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/AbstractValidatingSignableXMLObject.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/AbstractValidatingSignableXMLObject.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/AbstractValidatingSignableXMLObject.java 17 Aug 2012 15:17:06 -0000 1.1 @@ -0,0 +1,116 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml; + +import java.util.Collections; +import java.util.List; + +import org.opensaml.xml.signature.AbstractSignableXMLObject; +import org.opensaml.xml.util.LazyList; +import org.opensaml.xml.validation.ValidatingXMLObject; +import org.opensaml.xml.validation.ValidationException; +import org.opensaml.xml.validation.Validator; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Extension of {@link org.opensaml.xml.signature.AbstractSignableXMLObject} that implements + * {@link org.opensaml.xml.validation.ValidatingXMLObject}. + */ +public abstract class AbstractValidatingSignableXMLObject extends AbstractSignableXMLObject implements + ValidatingXMLObject { + + /** Class logger. */ + private final Logger log = LoggerFactory.getLogger(AbstractValidatingSignableXMLObject.class); + + /** Validators used to validate this XMLObject. */ + private List validators; + + /** + * Constructor. + * + * @param namespaceURI the namespace the element is in + * @param elementLocalName the local name of the XML element this Object represents + * @param namespacePrefix the prefix for the given namespace + */ + protected AbstractValidatingSignableXMLObject(String namespaceURI, String elementLocalName, String namespacePrefix) { + super(namespaceURI, elementLocalName, namespacePrefix); + validators = new LazyList(); + } + + /** {@inheritDoc} */ + public List getValidators() { + if (validators.size() > 0) { + return Collections.unmodifiableList(validators); + } + + return null; + } + + /** {@inheritDoc} */ + public void registerValidator(Validator validator) { + if (validator != null) { + validators.add(validator); + } + } + + /** {@inheritDoc} */ + public void deregisterValidator(Validator validator) { + validators.remove(validator); + } + + /** {@inheritDoc} */ + @SuppressWarnings("unchecked") + public void validate(boolean validateDescendants) throws ValidationException { + for (Validator validator : validators) { + log.debug("Validating {} using Validator class {}", getElementQName(), validator.getClass().getName()); + validator.validate(this); + } + + if (validateDescendants) { + log.debug("Validating descendants of {}", getElementQName()); + validateChildren(this); + } + } + + /** + * Recursive method used to validate all the children of the given XMLObject that implement + * {@link ValidatingXMLObject}. Note, this can be a very expensive operation. + * + * @param xmlObject xmlObject whose descendants should be validated + * + * @throws ValidationException thrown if one of the child objects do not validate + */ + protected void validateChildren(XMLObject xmlObject) throws ValidationException { + for (XMLObject childObject : xmlObject.getOrderedChildren()) { + if (childObject == null) { + continue; + } + + if (childObject instanceof ValidatingXMLObject) { + ((ValidatingXMLObject) childObject).validate(false); + } else { + log.debug("{} does not implement ValidatingXMLObject, ignoring it.", childObject.getElementQName()); + } + + if (childObject.hasChildren()) { + validateChildren(childObject); + } + } + } +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/AbstractXMLObject.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/AbstractXMLObject.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/AbstractXMLObject.java 17 Aug 2012 15:17:07 -0000 1.1 @@ -0,0 +1,568 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml; + +import java.util.Collections; +import java.util.List; +import java.util.Set; + +import javax.xml.namespace.QName; + +import org.opensaml.xml.schema.XSBooleanValue; +import org.opensaml.xml.util.DatatypeHelper; +import org.opensaml.xml.util.IDIndex; +import org.opensaml.xml.util.XMLConstants; +import org.opensaml.xml.util.XMLHelper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.w3c.dom.Element; + +/** + * An abstract implementation of XMLObject. + */ +public abstract class AbstractXMLObject implements XMLObject { + + /** Class logger. */ + private final Logger log = LoggerFactory.getLogger(AbstractXMLObject.class); + + /** Parent of this element. */ + private XMLObject parent; + + /** The name of this element with namespace and prefix information. */ + private QName elementQname; + + /** Schema locations for this XML object. */ + private String schemaLocation; + + /** No-namespace schema locations for this XML object. */ + private String noNamespaceSchemaLocation; + + /** The schema type of this element with namespace and prefix information. */ + private QName typeQname; + + /** DOM Element representation of this object. */ + private Element dom; + + /** The value of the xsi:nil attribute. */ + private XSBooleanValue nil; + + /** The namespace manager for this XML object. */ + private NamespaceManager nsManager; + + /** + * Mapping of ID attributes to XMLObjects in the subtree rooted at this object. This allows constant-time + * dereferencing of ID-typed attributes within the subtree. + */ + private final IDIndex idIndex; + + /** + * Constructor. + * + * @param namespaceURI the namespace the element is in + * @param elementLocalName the local name of the XML element this Object represents + * @param namespacePrefix the prefix for the given namespace + */ + protected AbstractXMLObject(String namespaceURI, String elementLocalName, String namespacePrefix) { + nsManager = new NamespaceManager(this); + idIndex = new IDIndex(this); + elementQname = XMLHelper.constructQName(namespaceURI, elementLocalName, namespacePrefix); + if(namespaceURI != null){ + setElementNamespacePrefix(namespacePrefix); + } + } + + /** {@inheritDoc} */ + public void addNamespace(Namespace newNamespace) { + getNamespaceManager().registerNamespace(newNamespace); + } + + /** {@inheritDoc} */ + public void detach(){ + releaseParentDOM(true); + parent = null; + } + + /** {@inheritDoc} */ + public Element getDOM() { + return dom; + } + + /** {@inheritDoc} */ + public QName getElementQName() { + return new QName(elementQname.getNamespaceURI(), elementQname.getLocalPart(), elementQname.getPrefix()); + } + + /** {@inheritDoc} */ + public IDIndex getIDIndex() { + return idIndex; + } + + /** {@inheritDoc} */ + public NamespaceManager getNamespaceManager() { + return nsManager; + } + + /** {@inheritDoc} */ + public Set getNamespaces() { + return Collections.unmodifiableSet(getNamespaceManager().getNamespaces()); + } + + /** {@inheritDoc} */ + public String getNoNamespaceSchemaLocation() { + return noNamespaceSchemaLocation; + } + + /** + * Gets the parent of this element. + * + * @return the parent of this element + */ + public XMLObject getParent() { + return parent; + } + + /** {@inheritDoc} */ + public String getSchemaLocation() { + return schemaLocation; + } + + /** {@inheritDoc} */ + public QName getSchemaType() { + return typeQname; + } + + /** {@inheritDoc} */ + public boolean hasChildren() { + List children = getOrderedChildren(); + return children != null && children.size() > 0; + } + + /** {@inheritDoc} */ + public boolean hasParent() { + return getParent() != null; + } + + /** + * A helper function for derived classes. This method should be called when the value of a + * namespace-qualified attribute changes. + * + * @param attributeName the attribute name + * @param hasValue true to indicate that the attribute has a value, false to indicate it has no value + */ + protected void manageQualifiedAttributeNamespace(QName attributeName, boolean hasValue) { + if (hasValue) { + getNamespaceManager().registerAttributeName(attributeName); + } else { + getNamespaceManager().deregisterAttributeName(attributeName); + } + } + + /** + * A helper function for derived classes. This checks for semantic equality between two QNames if it they are + * different invalidates the DOM. It returns the normalized value so subclasses just have to go. this.foo = + * prepareForAssignment(this.foo, foo); + * + * @param oldValue - the current value + * @param newValue - the new value + * + * @return the value that should be assigned + * + * @deprecated replacement {@link #prepareAttributeValueForAssignment(String, QName, QName)} + * or {@link #prepareElementContentForAssignment(QName, QName)} as appropriate + */ + protected QName prepareForAssignment(QName oldValue, QName newValue) { + if (oldValue == null) { + if (newValue != null) { + Namespace newNamespace = new Namespace(newValue.getNamespaceURI(), newValue.getPrefix()); + addNamespace(newNamespace); + releaseThisandParentDOM(); + return newValue; + } else { + return null; + } + } + + if (!oldValue.equals(newValue)) { + if (newValue != null) { + Namespace newNamespace = new Namespace(newValue.getNamespaceURI(), newValue.getPrefix()); + addNamespace(newNamespace); + } + releaseThisandParentDOM(); + } + + return newValue; + } + + /** + * A helper function for derived classes. This checks for semantic equality between two QNames if it they are + * different invalidates the DOM. It returns the normalized value so subclasses just have to go. this.foo = + * prepareElementContentForAssignment(this.foo, foo); + * + * @param oldValue - the current value + * @param newValue - the new value + * + * @return the value that should be assigned + */ + protected QName prepareElementContentForAssignment(QName oldValue, QName newValue) { + if (oldValue == null) { + if (newValue != null) { + getNamespaceManager().registerContentValue(newValue); + releaseThisandParentDOM(); + return newValue; + } else { + return null; + } + } + + // Old value was not null, so go ahead and deregister it + getNamespaceManager().deregisterContentValue(); + + if (!oldValue.equals(newValue)) { + if (newValue != null) { + getNamespaceManager().registerContentValue(newValue); + } + releaseThisandParentDOM(); + } + + return newValue; + } + + + /** + * A helper function for derived classes. This checks for semantic equality between two QNames if it they are + * different invalidates the DOM. It returns the normalized value so subclasses just have to go. this.foo = + * prepareAttributeValueForAssignment(this.foo, foo); + * + * @param attributeID - unique identifier of the attribute in the content model within this XMLObject, used to + * identify the attribute within the XMLObject's NamespaceManager + * @param oldValue - the current value + * @param newValue - the new value + * + * @return the value that should be assigned + */ + protected QName prepareAttributeValueForAssignment(String attributeID, QName oldValue, QName newValue) { + if (oldValue == null) { + if (newValue != null) { + getNamespaceManager().registerAttributeValue(attributeID, newValue); + releaseThisandParentDOM(); + return newValue; + } else { + return null; + } + } + + // Old value was not null, so go ahead and deregister it + getNamespaceManager().deregisterAttributeValue(attributeID); + + if (!oldValue.equals(newValue)) { + if (newValue != null) { + getNamespaceManager().registerAttributeValue(attributeID, newValue); + } + releaseThisandParentDOM(); + } + + return newValue; + } + + /** + * A helper function for derived classes. This 'nornmalizes' newString and then if it is different from oldString + * invalidates the DOM. It returns the normalized value so subclasses just have to go. this.foo = + * prepareForAssignment(this.foo, foo); + * + * @param oldValue - the current value + * @param newValue - the new value + * + * @return the value that should be assigned + */ + protected String prepareForAssignment(String oldValue, String newValue) { + String newString = DatatypeHelper.safeTrimOrNullString(newValue); + + if (!DatatypeHelper.safeEquals(oldValue, newString)) { + releaseThisandParentDOM(); + } + + return newString; + } + + /** + * A helper function for derived classes that checks to see if the old and new value are equal and if so releases + * the cached dom. Derived classes are expected to use this thus: + * this.foo = prepareForAssignment(this.foo, foo); + * + * + * This method will do a (null) safe compare of the objects and will also invalidate the DOM if appropriate + * + * @param - type of object being compared and assigned + * @param oldValue - current value + * @param newValue - proposed new value + * + * @return The value to assign to the saved Object. + */ + protected T prepareForAssignment(T oldValue, T newValue) { + if (oldValue == null) { + if (newValue != null) { + releaseThisandParentDOM(); + return newValue; + } else { + return null; + } + } + + if (!oldValue.equals(newValue)) { + releaseThisandParentDOM(); + } + + return newValue; + } + + /** + * A helper function for derived classes, similar to assignString, but for (singleton) SAML objects. It is + * indifferent to whether either the old or the new version of the value is null. Derived classes are expected to + * use this thus: + * this.foo = prepareForAssignment(this.foo, foo); + * + * + * This method will do a (null) safe compare of the objects and will also invalidate the DOM if appropriate + * + * @param type of object being compared and assigned + * @param oldValue current value + * @param newValue proposed new value + * + * @return The value to assign to the saved Object. + */ + protected T prepareForAssignment(T oldValue, T newValue) { + + if (newValue != null && newValue.hasParent()) { + throw new IllegalArgumentException(newValue.getClass().getName() + + " cannot be added - it is already the child of another SAML Object"); + } + + if (oldValue == null) { + if (newValue != null) { + releaseThisandParentDOM(); + newValue.setParent(this); + idIndex.registerIDMappings(newValue.getIDIndex()); + return newValue; + + } else { + return null; + } + } + + if (!oldValue.equals(newValue)) { + oldValue.setParent(null); + releaseThisandParentDOM(); + idIndex.deregisterIDMappings(oldValue.getIDIndex()); + if (newValue != null) { + newValue.setParent(this); + idIndex.registerIDMappings(newValue.getIDIndex()); + } + } + + return newValue; + } + + /** + * A helper function for derived classes. The mutator/setter method for any ID-typed attributes should call this + * method in order to handle getting the old value removed from the ID-to-XMLObject mapping, and the new value added + * to the mapping. + * + * @param oldID the old value of the ID-typed attribute + * @param newID the new value of the ID-typed attribute + */ + protected void registerOwnID(String oldID, String newID) { + String newString = DatatypeHelper.safeTrimOrNullString(newID); + + if (!DatatypeHelper.safeEquals(oldID, newString)) { + if (oldID != null) { + idIndex.deregisterIDMapping(oldID); + } + + if (newString != null) { + idIndex.registerIDMapping(newString, this); + } + } + } + + /** {@inheritDoc} */ + public void releaseChildrenDOM(boolean propagateRelease) { + log.trace("Releasing cached DOM reprsentation for children of {} with propagation set to {}", + getElementQName(), propagateRelease); + if (getOrderedChildren() != null) { + for (XMLObject child : getOrderedChildren()) { + if (child != null) { + child.releaseDOM(); + if (propagateRelease) { + child.releaseChildrenDOM(propagateRelease); + } + } + } + } + } + + /** {@inheritDoc} */ + public void releaseDOM() { + log.trace("Releasing cached DOM reprsentation for {}", getElementQName()); + setDOM(null); + } + + /** {@inheritDoc} */ + public void releaseParentDOM(boolean propagateRelease) { + log.trace("Releasing cached DOM reprsentation for parent of {} with propagation set to {}", getElementQName(), + propagateRelease); + XMLObject parentElement = getParent(); + if (parentElement != null) { + parent.releaseDOM(); + if (propagateRelease) { + parent.releaseParentDOM(propagateRelease); + } + } + } + + /** + * A convience method that is equal to calling {@link #releaseDOM()} then {@link #releaseChildrenDOM(boolean)} with + * the release being propogated. + */ + public void releaseThisAndChildrenDOM() { + if (getDOM() != null) { + releaseDOM(); + releaseChildrenDOM(true); + } + } + + /** + * A convience method that is equal to calling {@link #releaseDOM()} then {@link #releaseParentDOM(boolean)} with + * the release being propogated. + */ + public void releaseThisandParentDOM() { + if (getDOM() != null) { + releaseDOM(); + releaseParentDOM(true); + } + } + + /** {@inheritDoc} */ + public void removeNamespace(Namespace namespace) { + getNamespaceManager().deregisterNamespace(namespace); + } + + /** {@inheritDoc} */ + public XMLObject resolveID(String id) { + return idIndex.lookup(id); + } + + /** {@inheritDoc} */ + public XMLObject resolveIDFromRoot(String id) { + XMLObject root = this; + while (root.hasParent()) { + root = root.getParent(); + } + return root.resolveID(id); + } + + /** {@inheritDoc} */ + public void setDOM(Element newDom) { + dom = newDom; + } + + /** + * Sets the prefix for this element's namespace. + * + * @param prefix the prefix for this element's namespace + */ + public void setElementNamespacePrefix(String prefix) { + if (prefix == null) { + elementQname = new QName(elementQname.getNamespaceURI(), elementQname.getLocalPart()); + } else { + elementQname = new QName(elementQname.getNamespaceURI(), elementQname.getLocalPart(), prefix); + } + getNamespaceManager().registerElementName(elementQname); + } + + /** + * Sets the element QName. + * + * @param elementQName the element's QName + */ + protected void setElementQName(QName elementQName) { + this.elementQname = XMLHelper.constructQName(elementQName.getNamespaceURI(), elementQName.getLocalPart(), + elementQName.getPrefix()); + getNamespaceManager().registerElementName(this.elementQname); + } + + /** {@inheritDoc} */ + public void setNoNamespaceSchemaLocation(String location) { + noNamespaceSchemaLocation = DatatypeHelper.safeTrimOrNullString(location); + manageQualifiedAttributeNamespace(XMLConstants.XSI_NO_NAMESPACE_SCHEMA_LOCATION_ATTRIB_NAME, schemaLocation != null); + } + + /** {@inheritDoc} */ + public void setParent(XMLObject newParent) { + parent = newParent; + } + + /** {@inheritDoc} */ + public void setSchemaLocation(String location) { + schemaLocation = DatatypeHelper.safeTrimOrNullString(location); + manageQualifiedAttributeNamespace(XMLConstants.XSI_SCHEMA_LOCATION_ATTRIB_NAME, schemaLocation != null); + } + + /** + * Sets a given QName as the schema type for the Element represented by this XMLObject. This will register the namespace + * for the type as well as for the xsi:type qualified attribute name with the namespace manager for this XMLObject. + * If null is passed, the type name and xsi:type name will be deregistered. + * + * @param type the schema type + */ + protected void setSchemaType(QName type) { + typeQname = type; + getNamespaceManager().registerElementType(typeQname); + manageQualifiedAttributeNamespace(XMLConstants.XSI_TYPE_ATTRIB_NAME, typeQname != null); + } + + /** {@inheritDoc} */ + public Boolean isNil() { + if (nil != null) { + return nil.getValue(); + } + + return Boolean.FALSE; + } + + /** {@inheritDoc} */ + public XSBooleanValue isNilXSBoolean() { + return nil; + } + + /** {@inheritDoc} */ + public void setNil(Boolean newNil) { + if (newNil != null) { + nil = prepareForAssignment(nil, new XSBooleanValue(newNil, false)); + } else { + nil = prepareForAssignment(nil, null); + } + manageQualifiedAttributeNamespace(XMLConstants.XSI_NIL_ATTRIB_NAME, nil != null); + } + + /** {@inheritDoc} */ + public void setNil(XSBooleanValue newNil) { + nil = prepareForAssignment(nil, newNil); + manageQualifiedAttributeNamespace(XMLConstants.XSI_NIL_ATTRIB_NAME, nil != null); + } + +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/AbstractXMLObjectBuilder.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/AbstractXMLObjectBuilder.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/AbstractXMLObjectBuilder.java 17 Aug 2012 15:17:07 -0000 1.1 @@ -0,0 +1,71 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml; + +import javax.xml.namespace.QName; + +import org.opensaml.xml.util.XMLHelper; +import org.w3c.dom.Element; + +/** + * Base implementation for XMLObject builders. + * + * Note: This class only works with {@link org.opensaml.xml.AbstractXMLObject}s + * + * @param the XMLObject type that this builder produces + */ +public abstract class AbstractXMLObjectBuilder implements + XMLObjectBuilder { + + /** {@inheritDoc} */ + public XMLObjectType buildObject(QName objectName){ + return buildObject(objectName.getNamespaceURI(), objectName.getLocalPart(), objectName.getPrefix()); + } + + /** {@inheritDoc} */ + public XMLObjectType buildObject(QName objectName, QName schemaType){ + return buildObject(objectName.getNamespaceURI(), objectName.getLocalPart(), objectName.getPrefix(), schemaType); + } + + /** {@inheritDoc} */ + public abstract XMLObjectType buildObject(String namespaceURI, String localName, String namespacePrefix); + + /** {@inheritDoc} */ + public XMLObjectType buildObject(String namespaceURI, String localName, String namespacePrefix, QName schemaType) { + XMLObjectType xmlObject; + + xmlObject = buildObject(namespaceURI, localName, namespacePrefix); + ((AbstractXMLObject) xmlObject).setSchemaType(schemaType); + + return xmlObject; + } + + /** {@inheritDoc} */ + public XMLObjectType buildObject(Element element) { + XMLObjectType xmlObject; + + String localName = element.getLocalName(); + String nsURI = element.getNamespaceURI(); + String nsPrefix = element.getPrefix(); + QName schemaType = XMLHelper.getXSIType(element); + + xmlObject = buildObject(nsURI, localName, nsPrefix, schemaType); + + return xmlObject; + } +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/AttributeExtensibleXMLObject.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/AttributeExtensibleXMLObject.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/AttributeExtensibleXMLObject.java 17 Aug 2012 15:17:06 -0000 1.1 @@ -0,0 +1,35 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml; + +import org.opensaml.xml.util.AttributeMap; + +/** + * An interface for XMLObjects that represent DOM elements that support + * the XML Schema anyAttribute construct. + */ +public interface AttributeExtensibleXMLObject extends XMLObject { + + /** + * Gets a mutable map of the attributes. The map key is the namespace qualified name of the attribute, + * the map value is the value of the attribute. + * + * @return a map of the attributes + */ + public AttributeMap getUnknownAttributes(); +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/BaseBearing.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/BaseBearing.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/BaseBearing.java 17 Aug 2012 15:17:06 -0000 1.1 @@ -0,0 +1,51 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml; + +import javax.xml.namespace.QName; + +import org.opensaml.xml.util.XMLConstants; + +/** + * Interface for element having a @xml:base attribute. + * + */ +public interface BaseBearing { + + /** The base attribute local name. */ + public static final String XML_BASE_ATTR_LOCAL_NAME = "base"; + + /** The xml:base qualified attribute name. */ + public static final QName XML_BASE_ATTR_NAME = + new QName(XMLConstants.XML_NS, XML_BASE_ATTR_LOCAL_NAME, XMLConstants.XML_PREFIX); + + /** + * Returns the @xml:base attribute value. + * + * @return The @xml:base attribute value or null. + */ + public String getXMLBase(); + + /** + * Sets the @xml:base attribute value. + * + * @param newBase The @xml:base attribute value + */ + public void setXMLBase(String newBase); + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/Configuration.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/Configuration.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/Configuration.java 17 Aug 2012 15:17:06 -0000 1.1 @@ -0,0 +1,403 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml; + +import java.security.NoSuchAlgorithmException; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CopyOnWriteArraySet; + +import javax.crypto.Cipher; +import javax.crypto.NoSuchPaddingException; +import javax.xml.namespace.QName; +import javax.xml.parsers.DocumentBuilderFactory; + +import org.opensaml.xml.io.Marshaller; +import org.opensaml.xml.io.MarshallerFactory; +import org.opensaml.xml.io.Unmarshaller; +import org.opensaml.xml.io.UnmarshallerFactory; +import org.opensaml.xml.parse.ParserPool; +import org.opensaml.xml.security.SecurityConfiguration; +import org.opensaml.xml.util.XMLConstants; +import org.opensaml.xml.validation.ValidatorSuite; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.w3c.dom.Element; + +/** Class for loading library configuration files and retrieving the configured components. */ +public class Configuration { + + /** Default object provider. */ + private static QName defaultProvider = new QName(XMLConstants.XMLTOOLING_CONFIG_NS, + XMLConstants.XMLTOOLING_DEFAULT_OBJECT_PROVIDER); + + /** Object provider configuration elements indexed by QName. */ + private static Map configuredObjectProviders = new ConcurrentHashMap(0); + + /** Validator suite configuration elements indexed by suite IDs. */ + private static Map validatorSuiteConfigurations = new ConcurrentHashMap(0); + + /** Configured XMLObject builder factory. */ + private static XMLObjectBuilderFactory builderFactory = new XMLObjectBuilderFactory(); + + /** Configured XMLObject marshaller factory. */ + private static MarshallerFactory marshallerFactory = new MarshallerFactory(); + + /** Configured XMLObject unmarshaller factory. */ + private static UnmarshallerFactory unmarshallerFactory = new UnmarshallerFactory(); + + /** Configured ValidatorSuites. */ + private static Map validatorSuites = new ConcurrentHashMap(5); + + /** Configured set of attribute QNames which have been globally registered as having an ID type. */ + private static Set idAttributeNames = new CopyOnWriteArraySet(); + + /** Configured global security configuration information. */ + private static SecurityConfiguration globalSecurityConfig; + + /** Configured parser pool. */ + private static ParserPool parserPool; + + /** Constructor. */ + protected Configuration() { + + } + + /** + * Get the currently configured ParserPool instance. + * + * @return the currently ParserPool + */ + public static ParserPool getParserPool() { + return parserPool; + } + + /** + * Set the currently configured ParserPool instance. + * + * @param newParserPool the new ParserPool instance to configure + */ + public static void setParserPool(ParserPool newParserPool) { + parserPool = newParserPool; + } + + /** + * Gets the QName for the object provider that will be used for XMLObjects that do not have a registered object + * provider. + * + * @return the QName for the default object provider + */ + public static QName getDefaultProviderQName() { + return defaultProvider; + } + + /** + * Adds an object provider to this configuration. + * + * @param providerName the name of the object provider, corresponding to the element name or type name that the + * builder, marshaller, and unmarshaller operate on + * @param builder the builder for that given provider + * @param marshaller the marshaller for the provider + * @param unmarshaller the unmarshaller for the provider + */ + public static void registerObjectProvider(QName providerName, XMLObjectBuilder builder, Marshaller marshaller, + Unmarshaller unmarshaller) { + Logger log = getLogger(); + log.debug("Registering new builder, marshaller, and unmarshaller for {}", providerName); + builderFactory.registerBuilder(providerName, builder); + marshallerFactory.registerMarshaller(providerName, marshaller); + unmarshallerFactory.registerUnmarshaller(providerName, unmarshaller); + } + + /** + * Removes the builder, marshaller, and unmarshaller registered to the given key. + * + * @param key the key of the builder, marshaller, and unmarshaller to be removed + */ + public static void deregisterObjectProvider(QName key) { + Logger log = getLogger(); + log.debug("Unregistering builder, marshaller, and unmarshaller for {}", key); + configuredObjectProviders.remove(key); + builderFactory.deregisterBuilder(key); + marshallerFactory.deregisterMarshaller(key); + unmarshallerFactory.deregisterUnmarshaller(key); + } + + /** + * Gets the XMLObject builder factory that has been configured with information from loaded configuration files. + * + * @return the XMLObject builder factory + */ + public static XMLObjectBuilderFactory getBuilderFactory() { + return builderFactory; + } + + /** + * Gets the XMLObject marshaller factory that has been configured with information from loaded configuration files. + * + * @return the XMLObject marshaller factory + */ + public static MarshallerFactory getMarshallerFactory() { + return marshallerFactory; + } + + /** + * Gets the XMLObject unmarshaller factory that has been configured with information from loaded configuration + * files. + * + * @return the XMLObject unmarshaller factory + */ + public static UnmarshallerFactory getUnmarshallerFactory() { + return unmarshallerFactory; + } + + /** + * Registers a configured validator suite. + * + * @param suiteId the ID of the suite + * @param suite the configured suite + */ + public static void registerValidatorSuite(String suiteId, ValidatorSuite suite) { + validatorSuites.put(suiteId, suite); + } + + /** + * Removes a registered validator suite. + * + * @param suiteId the ID of the suite + */ + public static void deregisterValidatorSuite(String suiteId) { + validatorSuiteConfigurations.remove(suiteId); + validatorSuites.remove(suiteId); + } + + /** + * Gets a configured ValidatorSuite by its ID. + * + * @param suiteId the suite's ID + * + * @return the ValidatorSuite or null if no suite was registered under that ID + */ + public static ValidatorSuite getValidatorSuite(String suiteId) { + return validatorSuites.get(suiteId); + } + + /** + * Register an attribute as having a type of ID. + * + * @param attributeName the QName of the ID attribute to be registered + */ + public static void registerIDAttribute(QName attributeName) { + if (!idAttributeNames.contains(attributeName)) { + idAttributeNames.add(attributeName); + } + } + + /** + * Deregister an attribute as having a type of ID. + * + * @param attributeName the QName of the ID attribute to be de-registered + */ + public static void deregisterIDAttribute(QName attributeName) { + if (idAttributeNames.contains(attributeName)) { + idAttributeNames.remove(attributeName); + } + } + + /** + * Determine whether a given attribute is registered as having an ID type. + * + * @param attributeName the QName of the attribute to be checked for ID type. + * @return true if attribute is registered as having an ID type. + */ + public static boolean isIDAttribute(QName attributeName) { + return idAttributeNames.contains(attributeName); + } + + /** + * Get the global security configuration. + * + * @return the global security configuration instance + */ + public static SecurityConfiguration getGlobalSecurityConfiguration() { + return globalSecurityConfig; + } + + /** + * Set the global security configuration. + * + * @param config the new global security configuration instance + */ + public static void setGlobalSecurityConfiguration(SecurityConfiguration config) { + globalSecurityConfig = config; + } + + /** + * Validates that the system is not using the horribly buggy Sun JAXP implementation. + */ + public static void validateNonSunJAXP() { + Logger log = getLogger(); + String builderFactoryClass = DocumentBuilderFactory.newInstance().getClass().getName(); + log.debug("VM using JAXP parser {}", builderFactoryClass); + + if (builderFactoryClass.startsWith("com.sun")) { + String errorMsg = "\n\n\nOpenSAML requires an xml parser that supports JAXP 1.3 and DOM3.\n" + + "The JVM is currently configured to use the Sun XML parser, which is known\n" + + "to be buggy and can not be used with OpenSAML. Please endorse a functional\n" + + "JAXP library(ies) such as Xerces and Xalan. For instructions on how to endorse\n" + + "a new parser see http://java.sun.com/j2se/1.5.0/docs/guide/standards/index.html\n\n\n"; + + log.error(errorMsg); + throw new Error(errorMsg); + } + } + + /** + * Validates that the set of security providers configured in the JVM supports required cryptographic capabilities, + * for example for the XML Encryption and XML Signature specifications. + * + * Depending on the requirements of the calling code, failure to fully support encryption and signature requirements + * may or may not be significant, so return a status flag to let the caller make that determination. + * + * @return false if one or more capablities are not present, otherwise true + */ + public static boolean validateJCEProviders() { + Logger log = getLogger(); + boolean ret = true; + + // XML Encryption spec requires AES support (128 and 256). + // Some JRE's are known to ship with no JCE's that support + // the ISO10126Padding padding scheme. + + String errorMsgAESPadding = "The JCE providers currently configured in the JVM do not support\n" + + "required capabilities for XML Encryption, either the 'AES' cipher algorithm\n" + + "or the 'ISO10126Padding' padding scheme\n"; + + try { + Cipher.getInstance("AES/CBC/ISO10126Padding"); + } catch (NoSuchAlgorithmException e) { + // IBM JCE returns this as the top-level exception even for the unsupported padding case. :-( + // Otherwise would be nice to make the error msg more specific. + log.warn(errorMsgAESPadding); + ret = false; + } catch (NoSuchPaddingException e) { + log.warn(errorMsgAESPadding); + ret = false; + } + + // Could do more tests here as needed. + + return ret; + } + + /** + * Adds an object provider to this configuration. + * + * @param providerName the name of the object provider, corresponding to the element name or type name that the + * builder, marshaller, and unmarshaller operate on + * @param builder the builder for that given provider + * @param marshaller the marshaller for the provider + * @param unmarshaller the unmarshaller for the provider + * @param configuration optional XML configuration snippet + * + * @deprecated this method is deprecated with no replacement + */ + public static void registerObjectProvider(QName providerName, XMLObjectBuilder builder, Marshaller marshaller, + Unmarshaller unmarshaller, Element configuration) { + Logger log = getLogger(); + log.debug("Registering new builder, marshaller, and unmarshaller for {}", providerName); + if (configuration != null) { + configuredObjectProviders.put(providerName, configuration); + } + builderFactory.registerBuilder(providerName, builder); + marshallerFactory.registerMarshaller(providerName, marshaller); + unmarshallerFactory.registerUnmarshaller(providerName, unmarshaller); + } + + /** + * Gets a clone of the configuration element for a qualified element. Note that this configuration reflects the + * state of things as they were when the configuration was loaded, applications may have programmatically removed + * builder, marshallers, and unmarshallers during runtime. + * + * @param qualifedName the namespace qualifed element name of the schema type of the object provider + * + * @return the object provider configuration element or null if no object provider is configured with that name + * + * @deprecated this method is deprecated with no replacement + */ + public static Element getObjectProviderConfiguration(QName qualifedName) { + Element configElement = configuredObjectProviders.get(qualifedName); + if (configElement != null) { + return (Element) configElement.cloneNode(true); + } + return null; + } + + /** + * Registers a configured validator suite. + * + * @param suiteId the ID of the suite + * @param suite the configured suite + * @param configuration optional XML configuration information + * + * @deprecated this method is deprecated with no replacement + */ + public static void registerValidatorSuite(String suiteId, ValidatorSuite suite, Element configuration) { + if (configuration != null) { + validatorSuiteConfigurations.put(suiteId, configuration); + } + validatorSuites.put(suiteId, suite); + } + + /** + * Gets a clone of the ValidatorSuite configuration element for the ID. Note that this configuration reflects the + * state of things as they were when the configuration was loaded, applications may have programmatically removed + * altered the suite during runtime. + * + * @param suiteId the ID of the ValidatorSuite whose configuration is to be retrieved + * + * @return the validator suite configuration element or null if no suite is configured with that ID + * + * @deprecated this method is deprecated with no replacement + */ + public static Element getValidatorSuiteConfiguration(String suiteId) { + Element configElement = validatorSuiteConfigurations.get(suiteId); + if (configElement != null) { + return (Element) configElement.cloneNode(true); + } + + return null; + } + + /** + * Get an SLF4J Logger. + * + * @return a Logger instance + */ + private static Logger getLogger() { + return LoggerFactory.getLogger(Configuration.class); + } + + static { + validateJCEProviders(); + + // Default to registering the xml:id attribute as an ID type for all configurations + registerIDAttribute(new QName(javax.xml.XMLConstants.XML_NS_URI, "id")); + } +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/ConfigurationException.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/ConfigurationException.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/ConfigurationException.java 17 Aug 2012 15:17:07 -0000 1.1 @@ -0,0 +1,62 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml; + +/** + * An exception thrown when an error occurs loading information into {@link org.opensaml.xml.Configuration}. + */ +public class ConfigurationException extends Exception { + + /** Serial version UID. */ + private static final long serialVersionUID = -6777602050296807774L; + + /** + * Constructor. + */ + public ConfigurationException() { + super(); + } + + /** + * Constructor. + * + * @param message exception message + */ + public ConfigurationException(String message) { + super(message); + } + + /** + * Constructor. + * + * @param wrappedException exception to be wrapped by this one + */ + public ConfigurationException(Exception wrappedException) { + super(wrappedException); + } + + /** + * Constructor. + * + * @param message exception message + * @param wrappedException exception to be wrapped by this one + */ + public ConfigurationException(String message, Exception wrappedException) { + super(message, wrappedException); + } +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/ElementExtensibleXMLObject.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/ElementExtensibleXMLObject.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/ElementExtensibleXMLObject.java 17 Aug 2012 15:17:07 -0000 1.1 @@ -0,0 +1,44 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml; + +import java.util.List; + +import javax.xml.namespace.QName; + +/** + * An XMLObject whose content model contains "any" child elements. + */ +public interface ElementExtensibleXMLObject extends XMLObject { + + /** + * Gets the list of XMLObjects added to this XMLObject as part of the "any" content model. + * + * @return list of XMLObjects added to this XMLObject as part of the "any" content model + */ + public List getUnknownXMLObjects(); + + /** + * Gets the list of XMLObjects added to this XMLObject as part of the "any" content model, + * and which match the specified QName. + * + * @param typeOrName the QName of the statements to return + * @return list of XMLObjects added to this XMLObject as part of the "any" content model + */ + public List getUnknownXMLObjects(QName typeOrName); +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/IdBearing.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/IdBearing.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/IdBearing.java 17 Aug 2012 15:17:07 -0000 1.1 @@ -0,0 +1,51 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml; + +import javax.xml.namespace.QName; + +import org.opensaml.xml.util.XMLConstants; + +/** + * Interface for element having a @xml:id attribute. + * + */ +public interface IdBearing { + + /** The id attribute local name. */ + public static final String XML_ID_ATTR_LOCAL_NAME = "id"; + + /** The xml:id qualified attribute name. */ + public static final QName XML_ID_ATTR_NAME = + new QName(XMLConstants.XML_NS, XML_ID_ATTR_LOCAL_NAME, XMLConstants.XML_PREFIX); + + /** + * Returns the @xml:id attribute value. + * + * @return The @xml:id attribute value or null. + */ + public String getXMLId(); + + /** + * Sets the @xml:id attribute value. + * + * @param newId The @xml:id attribute value + */ + public void setXMLId(String newId); + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/LangBearing.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/LangBearing.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/LangBearing.java 17 Aug 2012 15:17:07 -0000 1.1 @@ -0,0 +1,51 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml; + +import javax.xml.namespace.QName; + +import org.opensaml.xml.util.XMLConstants; + +/** + * Interface for element having a @xml:lang attribute. + * + */ +public interface LangBearing { + + /** The lang attribute local name. */ + public static final String XML_LANG_ATTR_LOCAL_NAME = "lang"; + + /** The xml:lang qualified attribute name. */ + public static final QName XML_LANG_ATTR_NAME = + new QName(XMLConstants.XML_NS, XML_LANG_ATTR_LOCAL_NAME, XMLConstants.XML_PREFIX); + + /** + * Returns the @xml:lang attribute value. + * + * @return The @xml:lang attribute value or null. + */ + public String getXMLLang(); + + /** + * Sets the @xml:lang attribute value. + * + * @param newLang The @xml:lang attribute value + */ + public void setXMLLang(String newLang); + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/Namespace.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/Namespace.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/Namespace.java 17 Aug 2012 15:17:06 -0000 1.1 @@ -0,0 +1,184 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml; + +import org.opensaml.xml.util.DatatypeHelper; +import org.opensaml.xml.util.XMLConstants; + +/** Data structure for representing XML namespace attributes. */ +public class Namespace { + + /** URI of the namespace. */ + private String namespaceURI; + + /** Prefix of the namespace. */ + private String namespacePrefix; + + /** Always declare this namespace while marshalling? */ + private boolean alwaysDeclare; + + /** String representation of this namespace. */ + private String nsStr; + + /** Constructor. */ + public Namespace() { + + } + + /** + * Constructor. + * + * @param uri the URI of the namespace + * @param prefix the prefix of the namespace + */ + public Namespace(String uri, String prefix) { + namespaceURI = DatatypeHelper.safeTrimOrNullString(uri); + namespacePrefix = DatatypeHelper.safeTrimOrNullString(prefix); + nsStr = null; + } + + /** + * Gets the prefix of the namespace. + * + * @return the prefix of the namespace, may be null if this is a default namespace + */ + public String getNamespacePrefix() { + return namespacePrefix; + } + + /** + * Sets the prefix of the namespace. + * + * @param newPrefix the prefix of the namespace + */ + public void setNamespacePrefix(String newPrefix) { + namespacePrefix = DatatypeHelper.safeTrimOrNullString(newPrefix); + nsStr = null; + } + + /** + * Gets the URI of the namespace. + * + * @return the URI of the namespace + */ + public String getNamespaceURI() { + return namespaceURI; + } + + /** + * Sets the URI of the namespace. + * + * @param newURI the URI of the namespace + */ + public void setNamespaceURI(String newURI) { + namespaceURI = DatatypeHelper.safeTrimOrNullString(newURI); + nsStr = null; + } + + /** + * Gets wether this namespace should always be declared when marshalling, even if it was already declared on an + * ancestral element. + * + * @return true if this namespace should always be declared, false if not + * + * @deprecated use appropriate methods on the XMLObject's {@link NamespaceManager}. + */ + public boolean alwaysDeclare() { + return alwaysDeclare; + } + + /** + * Sets wether this namespace should always be declared when marshalling, even if it was already declared on an + * ancestral element. + * + * @param shouldAlwaysDeclare true if this namespace should always be declared, false if not + * + * @deprecated use appropriate methods on the XMLObject's {@link NamespaceManager}. + */ + public void setAlwaysDeclare(boolean shouldAlwaysDeclare) { + alwaysDeclare = shouldAlwaysDeclare; + } + + /** {@inheritDoc} */ + public String toString() { + if (nsStr == null) { + constructStringRepresentation(); + } + + return nsStr; + } + + /** {@inheritDoc} */ + public int hashCode() { + int hash = 1; + hash = hash * 31 + toString().hashCode(); + hash = hash * 31 + (alwaysDeclare ? 0 : 1); + return hash; + } + + /** + * Checks if the given object is the same as this Namespace. This is true if: + *
    + *
  • The given object is of type {@link Namespace}
  • + *
  • The given object's namespace URI is the same as this object's namespace URI
  • + *
  • The given object's namespace prefix is the same as this object's namespace prefix
  • + *
+ * + * @param obj {@inheritDoc} + * + * @return {@inheritDoc} + */ + public boolean equals(Object obj) { + if(obj == this){ + return true; + } + + if (obj instanceof Namespace) { + Namespace otherNamespace = (Namespace) obj; + if (DatatypeHelper.safeEquals(otherNamespace.getNamespaceURI(), getNamespaceURI())){ + if (DatatypeHelper.safeEquals(otherNamespace.getNamespacePrefix(), getNamespacePrefix())){ + return otherNamespace.alwaysDeclare() == alwaysDeclare(); + } + } + } + + return false; + } + + /** Constructs an XML namespace declaration string representing this namespace. */ + protected void constructStringRepresentation() { + StringBuffer stringRep = new StringBuffer(); + + stringRep.append(XMLConstants.XMLNS_PREFIX); + + if (namespacePrefix != null) { + stringRep.append(":"); + stringRep.append(namespacePrefix); + } + + stringRep.append("=\""); + + if (namespaceURI != null) { + stringRep.append(namespaceURI); + } + + stringRep.append("\""); + + nsStr = stringRep.toString(); + } +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/NamespaceManager.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/NamespaceManager.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/NamespaceManager.java 17 Aug 2012 15:17:06 -0000 1.1 @@ -0,0 +1,595 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml; + +import java.util.Collection; + +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import javax.xml.namespace.QName; + +import org.opensaml.xml.util.DatatypeHelper; +import org.opensaml.xml.util.LazyMap; +import org.opensaml.xml.util.LazySet; +import org.opensaml.xml.util.XMLConstants; + +/** + * A class which is responsible for managing XML namespace-related data for an {@link XMLObject}. + * + *

+ * Code which mutates the state of an XMLObject such that XML namespace-related data is also logically changed, + * should call the appropriate method, based on the type of change being made. + *

+ */ +public class NamespaceManager { + + /** The token used to represent the default namespace in {@link #getNonVisibleNamespacePrefixes()}. */ + public static final String DEFAULT_NS_TOKEN = "#default"; + + /** The 'xml' namespace. */ + private static final Namespace XML_NAMESPACE = + new Namespace(XMLConstants.XML_NS, XMLConstants.XML_PREFIX); + + /** The 'xsi' namespace. */ + private static final Namespace XSI_NAMESPACE = + new Namespace(XMLConstants.XSI_NS, XMLConstants.XSI_PREFIX); + + /** The owning XMLObject. */ + private XMLObject owner; + + /** XMLObject name namespace. */ + private Namespace elementName; + + /** XMLObject type namespace. */ + private Namespace elementType; + + /** Explicitly declared namespaces. */ + private Set decls; + + /** Indeterminate namespace usage. */ + private Set usage; + + /** Registered namespaces of attribute names. */ + private Set attrNames; + + /** Registered namespaces of attribute values. */ + private Map attrValues; + + /** Registered namespaces of content values. */ + private Namespace contentValue; + + /** + * Constructor. + * + * @param owningObject the XMLObject whose namespace info is to be managed + */ + public NamespaceManager(XMLObject owningObject) { + owner = owningObject; + + decls = new LazySet(); + usage = new LazySet(); + attrNames = new LazySet(); + attrValues = new LazyMap(); + } + + /** + * From an QName representing a qualified attribute name, generate an attribute ID + * suitable for use in {@link #registerAttributeValue(String, QName)} + * and {@link #deregisterAttributeValue(String)}. + * + * @param name attribute name as a QName + * @return a string attribute ID + */ + public static String generateAttributeID(QName name) { + return name.toString(); + } + + /** + * Get the owning XMLObject instance. + * + * @return the owning XMLObject + */ + public XMLObject getOwner() { + return owner; + } + + /** + * Get the set of namespaces currently in use on the owning XMLObject. + * + * @return the set of namespaces + */ + public Set getNamespaces() { + Set namespaces = mergeNamespaceCollections(decls, usage, attrNames, attrValues.values()); + addNamespace(namespaces, getElementNameNamespace()); + addNamespace(namespaces, getElementTypeNamespace()); + addNamespace(namespaces, contentValue); + return namespaces; + } + + + /** + * Register usage of a namespace in some indeterminate fashion. + * + *

+ * Other methods which indicate specific usage should be preferred over this one. This + * method exists primarily for backward-compatibility support for {@link XMLObject#addNamespace(Namespace)}. + *

+ * + * @param namespace namespace to register + */ + public void registerNamespace(Namespace namespace) { + addNamespace(usage, namespace); + } + + /** + * Deregister usage of a namespace in some indeterminate fashion. + * + *

+ * Other methods which indicate specific usage should be preferred over this one. This + * method exists primarily for backward-compatibility support for {@link XMLObject#removeNamespace(Namespace)}. + *

+ * + * @param namespace namespace to deregister + */ + public void deregisterNamespace(Namespace namespace) { + removeNamespace(usage, namespace); + } + + /** + * Register a namespace declaration. + * + * @param namespace the namespace to register + */ + public void registerNamespaceDeclaration(Namespace namespace) { + namespace.setAlwaysDeclare(true); + addNamespace(decls, namespace); + } + + /** + * Deregister a namespace declaration. + * + * @param namespace the namespace to deregister + */ + public void deregisterNamespaceDeclaration(Namespace namespace) { + removeNamespace(decls, namespace); + } + + /** + * Register a namespace-qualified attribute name. + * + * @param attributeName the attribute name to register + */ + public void registerAttributeName(QName attributeName) { + if (checkQName(attributeName)) { + addNamespace(attrNames, buildNamespace(attributeName)); + } + } + + /** + * Deregister a namespace-qualified attribute name. + * + * @param attributeName the attribute name to deregister + */ + public void deregisterAttributeName(QName attributeName) { + if (checkQName(attributeName)) { + removeNamespace(attrNames, buildNamespace(attributeName)); + } + } + + /** + * Register a QName attribute value. + * + * @param attributeID unique identifier for the attribute within the XMLObject's content model + * @param attributeValue the QName value to register + */ + public void registerAttributeValue(String attributeID, QName attributeValue) { + if (checkQName(attributeValue)) { + attrValues.put(attributeID, buildNamespace(attributeValue)); + } + } + + /** + * Deregister a QName attribute value. + * + * @param attributeID unique identifier for the attribute within the XMLObject's content model + */ + public void deregisterAttributeValue(String attributeID) { + attrValues.remove(attributeID); + } + + /** + * Register a QName element content value. + * + * @param content the QName value to register + */ + public void registerContentValue(QName content) { + if (checkQName(content)) { + contentValue = buildNamespace(content); + } + } + + /** + * Deregister a QName content value. + * + */ + public void deregisterContentValue() { + contentValue = null; + } + + /** + * Obtain the set of namespace prefixes used in a non-visible manner on owning XMLObject + * and its children. + * + *

+ * The primary use case for this information is to support the inclusive prefixes + * information that may optionally be supplied as a part of XML exclusive canonicalization. + *

+ * + * @return the set of non-visibly used namespace prefixes + */ + public Set getNonVisibleNamespacePrefixes() { + LazySet prefixes = new LazySet(); + addPrefixes(prefixes, getNonVisibleNamespaces()); + return prefixes; + } + + /** + * Obtain the set of namespaces used in a non-visible manner on owning XMLObject + * and its children. + * + *

+ * The primary use case for this information is to support the inclusive prefixes + * information that may optionally be supplied as a part of XML exclusive canonicalization. + *

+ * + *

+ * The Namespace instances themselves will be copied before being returned, so + * modifications to them do not affect the actual Namespace instances in the + * underlying tree. The original alwaysDeclare property is not preserved. + *

+ * + * @return the set of non-visibly used namespaces + */ + public Set getNonVisibleNamespaces() { + LazySet nonVisibleCandidates = new LazySet(); + + // Collect each child's non-visible namespaces + List children = getOwner().getOrderedChildren(); + if (children != null) { + for(XMLObject child : getOwner().getOrderedChildren()) { + if (child != null) { + Set childNonVisibleNamespaces = child.getNamespaceManager().getNonVisibleNamespaces(); + if (childNonVisibleNamespaces != null && ! childNonVisibleNamespaces.isEmpty()) { + nonVisibleCandidates.addAll(childNonVisibleNamespaces); + } + } + } + } + + // Collect this node's non-visible candidate namespaces + nonVisibleCandidates.addAll(getNonVisibleNamespaceCandidates()); + + // Now subtract this object's visible namespaces + nonVisibleCandidates.removeAll(getVisibleNamespaces()); + + // As a special case, never return the 'xml' prefix. + nonVisibleCandidates.remove(XML_NAMESPACE); + + // What remains is the effective set of non-visible namespaces + // for the subtree rooted at this node. + return nonVisibleCandidates; + + } + + /** + * Get the set of all namespaces which are in scope within the subtree rooted + * at the owning XMLObject. + * + *

+ * The Namespace instances themselves will be copied before being returned, so + * modifications to them do not affect the actual Namespace instances in the + * underlying tree. The original alwaysDeclare property is not preserved. + *

+ * + * @return set of all namespaces in scope for the owning object + */ + public Set getAllNamespacesInSubtreeScope() { + LazySet namespaces = new LazySet(); + + // Collect namespaces for the subtree rooted at each child + List children = getOwner().getOrderedChildren(); + if (children != null) { + for(XMLObject child : getOwner().getOrderedChildren()) { + if (child != null) { + Set childNamespaces = child.getNamespaceManager().getAllNamespacesInSubtreeScope(); + if (childNamespaces != null && ! childNamespaces.isEmpty()) { + namespaces.addAll(childNamespaces); + } + } + } + } + + // Collect this node's namespaces. Copy before adding to the set. Do not preserve alwaysDeclare. + for (Namespace myNS : getNamespaces()) { + namespaces.add(copyNamespace(myNS)); + } + + return namespaces; + } + + /** + * Register the owning XMLObject's element name. + * + * @param name the element name to register + */ + public void registerElementName(QName name) { + if (checkQName(name)) { + elementName = buildNamespace(name); + } + } + + /** + * Register the owning XMLObject's element type, if explicitly declared via an xsi:type. + * + * @param type the element type to register + */ + public void registerElementType(QName type) { + if (type != null) { + if (checkQName(type)) { + elementType = buildNamespace(type); + } + } else { + elementType = null; + } + } + + /** + * Return a Namespace instance representing the namespace of the element name. + * + * @return the element name's namespace + */ + private Namespace getElementNameNamespace() { + if (elementName == null && checkQName(owner.getElementQName())) { + elementName = buildNamespace(owner.getElementQName()); + } + return elementName; + } + + /** + * Return a Namespace instance representing the namespace of the element type, if known. + * + * @return the element type's namespace + */ + private Namespace getElementTypeNamespace() { + if (elementType == null) { + QName type = owner.getSchemaType(); + if (type != null && checkQName(type)) { + elementType = buildNamespace(type); + } + } + return elementType; + } + + /** + * Build a {@link Namespace} instance from a {@link QName}. + * + * @param name the source QName + * @return a Namespace built using the information in the QName + */ + private Namespace buildNamespace(QName name) { + String uri = DatatypeHelper.safeTrimOrNullString(name.getNamespaceURI()); + if (uri == null) { + throw new IllegalArgumentException("A non-empty namespace URI must be supplied"); + } + String prefix = DatatypeHelper.safeTrimOrNullString(name.getPrefix()); + return new Namespace(uri, prefix); + } + + /** + * Add a Namespace to a set of Namespaces. Namespaces with identical URI and prefix will be treated as equivalent. + * An alwaysDeclare property of true will take precedence over a value of false. + * + * @param namespaces the set of namespaces + * @param newNamespace the namespace to add to the set + */ + private void addNamespace(Set namespaces, Namespace newNamespace) { + if (newNamespace == null) { + return; + } + + if (namespaces.size() == 0) { + namespaces.add(newNamespace); + return; + } + + for (Namespace namespace : namespaces) { + if (DatatypeHelper.safeEquals(namespace.getNamespaceURI(), newNamespace.getNamespaceURI()) && + DatatypeHelper.safeEquals(namespace.getNamespacePrefix(), newNamespace.getNamespacePrefix())) { + if (newNamespace.alwaysDeclare() && !namespace.alwaysDeclare()) { + // An alwaysDeclare=true trumps false. + // Don't modify the existing object in the set, merely swap them. + namespaces.remove(namespace); + namespaces.add(newNamespace); + return; + } else { + // URI and prefix match, alwaysDeclare does also, so just leave the original + return; + } + } + } + + namespaces.add(newNamespace); + } + + /** + * Remove a Namespace from a set of Namespaces. Equivalence of Namespace instances will be based + * on namespace URI and prefix only. The alwaysDeclare property will be ignored for + * purpose of equivalence. + * + * @param namespaces the set of namespaces + * @param oldNamespace the namespace to add to the set + */ + private void removeNamespace(Set namespaces, Namespace oldNamespace) { + if (oldNamespace == null) { + return; + } + + Iterator iter = namespaces.iterator(); + while (iter.hasNext()) { + Namespace namespace = iter.next(); + if (DatatypeHelper.safeEquals(namespace.getNamespaceURI(), oldNamespace.getNamespaceURI()) && + DatatypeHelper.safeEquals(namespace.getNamespacePrefix(), oldNamespace.getNamespacePrefix())) { + iter.remove(); + } + } + + } + + /** + * Merge 2 or more Namespace collections into a single set, with equivalence semantics as described + * in {@link #addNamespace(Set, Namespace)}. + * + * @param namespaces list of Namespaces to merge + * @return the a new set of merged Namespaces + */ + private Set mergeNamespaceCollections(Collection ... namespaces) { + LazySet newNamespaces = new LazySet(); + + for (Collection nsCollection : namespaces) { + for (Namespace ns : nsCollection) { + if (ns != null) { + addNamespace(newNamespaces, ns); + } + } + } + + return newNamespaces; + } + + /** + * Get the set of namespaces which are currently visibly-used on the owning XMLObject (only the owner, + * not its children). + * + *

+ * Namespaces returned in the set are copied from the ones held in the manager. The + * alwaysDeclare property is not preserved. + *

+ * + * @return the set of visibly-used namespaces + */ + private Set getVisibleNamespaces() { + LazySet namespaces = new LazySet(); + + // Add namespace from element name. + if (getElementNameNamespace() != null) { + namespaces.add(copyNamespace(getElementNameNamespace())); + } + + // Add xsi attribute prefix, if element carries an xsi:type. + if (getElementTypeNamespace() != null) { + namespaces.add(copyNamespace(XSI_NAMESPACE)); + } + + // Add namespaces from attribute names + for (Namespace attribName : attrNames) { + if (attribName != null) { + namespaces.add(copyNamespace(attribName)); + } + } + + return namespaces; + } + + /** + * Get the set of non-visibly used namespaces used on the owning XMLObject (only the owner, + * not the owner's children). + * + *

+ * Namespaces returned in the set are copied from the ones held in the manager. The + * alwaysDeclare property is not preserved. + *

+ * + * @return the set of non-visibly-used namespaces + */ + private Set getNonVisibleNamespaceCandidates() { + LazySet namespaces = new LazySet(); + + // Add xsi:type value's prefix, if element carries an xsi:type + if (getElementTypeNamespace() != null) { + namespaces.add(copyNamespace(getElementTypeNamespace())); + } + + // Add prefixes from attribute and content values + for (Namespace attribValue : attrValues.values()) { + if (attribValue != null) { + namespaces.add(copyNamespace(attribValue)); + } + } + if (contentValue != null) { + namespaces.add(copyNamespace(contentValue)); + } + + return namespaces; + } + + /** + * Get a copy of a Namespace. The alwaysDeclare property is not preserved. + * + * @param orig the namespace instance to copy + * @return a copy of the specified namespace + */ + private Namespace copyNamespace(Namespace orig) { + if (orig == null) { + return null; + } else { + return new Namespace(orig.getNamespaceURI(), orig.getNamespacePrefix()); + } + } + + /** + * Add the prefixes from a collection of namespaces to a set of prefixes. The + * value used to represent the default namespace will be normalized to {@link NamespaceManager#DEFAULT_NS_TOKEN}. + * + * @param prefixes the set of prefixes to which to add + * @param namespaces the source set of Namespaces + */ + private void addPrefixes(Set prefixes, Collection namespaces) { + for (Namespace ns : namespaces) { + String prefix = DatatypeHelper.safeTrimOrNullString(ns.getNamespacePrefix()); + if (prefix == null) { + prefix = DEFAULT_NS_TOKEN; + } + prefixes.add(prefix); + } + } + + /** + * Check whether the supplied QName contains non-empty namespace info and should + * be managed by the namespace manager. + * + * @param name the QName to check + * @return true if the QName contains non-empty namespace info and should be managed, false otherwise + */ + private boolean checkQName(QName name) { + return !DatatypeHelper.isEmpty(name.getNamespaceURI()); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/SpaceBearing.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/SpaceBearing.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/SpaceBearing.java 17 Aug 2012 15:17:06 -0000 1.1 @@ -0,0 +1,82 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml; + +import javax.xml.namespace.QName; + +import org.opensaml.xml.util.XMLConstants; + +/** + * Interface for element having a @xml:space attribute. + * + */ +public interface SpaceBearing { + + /** Enum representing the allowed values of the xml:space attribute. */ + public enum XMLSpaceEnum { + /** xml:space value "default". */ + DEFAULT, + /** xml:space value "preserve". */ + PRESERVE; + + // Unfortunately "default" is a reserved word in Java, so the enum value above has to be upper case + // and we have the mess below. + + /** {@inheritDoc} */ + public String toString() { + return super.toString().toLowerCase(); + } + + /** + * Parse a string value into an XMLSpaceEnum. + * + *

+ * The legal values are "default" and "preserve". + *

+ * + * @param value the value to parse + * @return the corresponding XMLSpaceEnum + */ + public static XMLSpaceEnum parseValue(String value) { + return XMLSpaceEnum.valueOf(value.toUpperCase()); + } + + } + + /** The space attribute local name. */ + public static final String XML_SPACE_ATTR_LOCAL_NAME = "space"; + + /** The xml:space qualified attribute name. */ + public static final QName XML_SPACE_ATTR_NAME = + new QName(XMLConstants.XML_NS, XML_SPACE_ATTR_LOCAL_NAME, XMLConstants.XML_PREFIX); + + /** + * Returns the @xml:space attribute value. + * + * @return The @xml:space attribute value or null. + */ + public XMLSpaceEnum getXMLSpace(); + + /** + * Sets the @xml:space attribute value. + * + * @param newSpace The @xml:space attribute value + */ + public void setXMLSpace(XMLSpaceEnum newSpace); + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/Version.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/Version.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/Version.java 17 Aug 2012 15:17:07 -0000 1.1 @@ -0,0 +1,105 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml; + +/** Class for printing the version of this library. */ +public final class Version { + + /** Name of the library. */ + private static final String NAME; + + /** Library version. */ + private static final String VERSION; + + /** Library major version number. */ + private static final int MAJOR_VERSION; + + /** Library minor version number. */ + private static final int MINOR_VERSION; + + /** Library micro version number. */ + private static final int MICRO_VERSION; + + /** Constructor. */ + private Version() { + } + + /** + * Main entry point to program. + * + * @param args command line arguments + */ + public static void main(String[] args) { + System.out.println(NAME + " version " + VERSION); + } + + /** + * Gets the name of the library. + * + * @return name of the library + */ + public static String getName() { + return NAME; + } + + /** + * Gets the version of the library. + * + * @return version of the library + */ + public static String getVersion() { + return VERSION; + } + + /** + * Gets the major version number of the library. + * + * @return major version number of the library + */ + public static int getMajorVersion() { + return MAJOR_VERSION; + } + + /** + * Gets the minor version number of the library. + * + * @return minor version number of the library + */ + public static int getMinorVersion() { + return MINOR_VERSION; + } + + /** + * Gets the micro version number of the library. + * + * @return micro version number of the library + */ + public static int getMicroVersion() { + return MICRO_VERSION; + } + + static { + Package pkg = Version.class.getPackage(); + NAME = pkg.getImplementationTitle().intern(); + VERSION = pkg.getImplementationVersion().intern(); + String[] versionParts = VERSION.split("\\."); + MAJOR_VERSION = Integer.parseInt(versionParts[0]); + MINOR_VERSION = Integer.parseInt(versionParts[1]); + MICRO_VERSION = Integer.parseInt(versionParts[2]); + } +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/XMLConfigurator.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/XMLConfigurator.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/XMLConfigurator.java 17 Aug 2012 15:17:06 -0000 1.1 @@ -0,0 +1,386 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.lang.reflect.Constructor; + +import javax.xml.namespace.QName; +import javax.xml.transform.Source; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamSource; +import javax.xml.validation.Schema; +import javax.xml.validation.SchemaFactory; + +import org.opensaml.xml.io.Marshaller; +import org.opensaml.xml.io.Unmarshaller; +import org.opensaml.xml.parse.BasicParserPool; +import org.opensaml.xml.parse.XMLParserException; +import org.opensaml.xml.util.DatatypeHelper; +import org.opensaml.xml.util.XMLConstants; +import org.opensaml.xml.util.XMLHelper; +import org.opensaml.xml.validation.Validator; +import org.opensaml.xml.validation.ValidatorSuite; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.w3c.dom.Attr; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; +import org.xml.sax.SAXException; + +/** + * Reads in an XML configuration and configures the XMLTooling library accordingly. + */ +public class XMLConfigurator { + + /** Class logger. */ + private final Logger log = LoggerFactory.getLogger(XMLConfigurator.class); + + /** Whether the XML configuration elements that configured object providers should be retained. */ + private boolean retainXMLConfiguration; + + /** Pool of parsers used to read and validate configurations. */ + private BasicParserPool parserPool; + + /** Schema used to validate configruation files. */ + private Schema configurationSchema; + + /** + * Constructor. + * + * @throws ConfigurationException thrown if the validation schema for configuration files can not be created + */ + public XMLConfigurator() throws ConfigurationException { + this(false); + } + + /** + * Constructor. + * + * @param retainXML whether to retain the XML configuration elements within the {@link Configuration}. + * + * @throws ConfigurationException thrown if the validation schema for configuration files can not be created + * + * @deprecated this method will be removed once {@link Configuration} no longer has the option to store the XML configuration fragements + */ + public XMLConfigurator(boolean retainXML) throws ConfigurationException { + retainXMLConfiguration = retainXML; + parserPool = new BasicParserPool(); + SchemaFactory factory = SchemaFactory.newInstance(javax.xml.XMLConstants.W3C_XML_SCHEMA_NS_URI); + Source schemaSource = new StreamSource(XMLConfigurator.class + .getResourceAsStream(XMLConstants.XMLTOOLING_SCHEMA_LOCATION)); + try { + configurationSchema = factory.newSchema(schemaSource); + + parserPool.setIgnoreComments(true); + parserPool.setIgnoreElementContentWhitespace(true); + parserPool.setSchema(configurationSchema); + } catch (SAXException e) { + throw new ConfigurationException("Unable to read XMLTooling configuration schema", e); + } + } + + /** + * Loads the configuration file(s) from the given file. If the file is a directory each file within the directory is + * loaded. + * + * @param configurationFile the configuration file(s) to be loaded + * + * @throws ConfigurationException thrown if the configuration file(s) can not be be read or invalid + */ + public void load(File configurationFile) throws ConfigurationException { + if (configurationFile == null || !configurationFile.canRead()) { + log.error("Unable to read configuration file {}", configurationFile); + } + + try { + if (configurationFile.isDirectory()) { + File[] configurations = configurationFile.listFiles(); + for (int i = 0; i < configurations.length; i++) { + log.debug("Parsing configuration file {}", configurations[i].getAbsolutePath()); + load(new FileInputStream(configurations[i])); + } + } else { + // Given file is not a directory so try to load it directly + log.debug("Parsing configuration file {}", configurationFile.getAbsolutePath()); + load(new FileInputStream(configurationFile)); + } + } catch (FileNotFoundException e) { + // ignore, we already have the files + } + } + + /** + * Loads a configuration file from an input stream. + * + * @param configurationStream configuration stream + * + * @throws ConfigurationException thrown if the given configuration is invalid or can not be read + */ + public void load(InputStream configurationStream) throws ConfigurationException { + try { + Document configuration = parserPool.parse(configurationStream); + load(configuration); + } catch (XMLParserException e) { + log.error("Invalid configuration file", e); + throw new ConfigurationException("Unable to create DocumentBuilder", e); + } + + } + + /** + * Loads the configuration docuement. + * + * @param configuration the configurationd document + * @throws ConfigurationException thrown if the configuration file(s) can not be be read or invalid + */ + public void load(Document configuration) throws ConfigurationException { + log.debug("Loading configuration from XML Document"); + log.trace("{}", XMLHelper.nodeToString(configuration.getDocumentElement())); + + // Schema validation + log.debug("Schema validating configuration Document"); + validateConfiguration(configuration); + log.debug("Configuration document validated"); + + load(configuration.getDocumentElement()); + } + + /** + * Loads a configuration after it's been schema validated. + * + * @param configurationRoot root of the configuration + * + * @throws ConfigurationException thrown if there is a problem processing the configuration + */ + protected void load(Element configurationRoot) throws ConfigurationException { + // Initialize object providers + NodeList objectProviders = configurationRoot.getElementsByTagNameNS(XMLConstants.XMLTOOLING_CONFIG_NS, + "ObjectProviders"); + if (objectProviders.getLength() > 0) { + log.debug("Preparing to load ObjectProviders"); + initializeObjectProviders((Element) objectProviders.item(0)); + log.debug("ObjectProviders load complete"); + } + + // Initialize validator suites + NodeList validatorSuitesNodes = configurationRoot.getElementsByTagNameNS(XMLConstants.XMLTOOLING_CONFIG_NS, + "ValidatorSuites"); + if (validatorSuitesNodes.getLength() > 0) { + log.debug("Preparing to load ValidatorSuites"); + initializeValidatorSuites((Element) validatorSuitesNodes.item(0)); + log.debug("ValidatorSuites load complete"); + } + + // Initialize ID attributes + NodeList idAttributesNodes = configurationRoot.getElementsByTagNameNS(XMLConstants.XMLTOOLING_CONFIG_NS, + "IDAttributes"); + if (idAttributesNodes.getLength() > 0) { + log.debug("Preparing to load IDAttributes"); + initializeIDAttributes((Element) idAttributesNodes.item(0)); + log.debug("IDAttributes load complete"); + } + } + + /** + * Intializes the object providers defined in the configuration file. + * + * @param objectProviders the configuration for the various object providers + * + * @throws ConfigurationException thrown if the configuration elements are invalid + */ + protected void initializeObjectProviders(Element objectProviders) throws ConfigurationException { + // Process ObjectProvider child elements + Element objectProvider; + Attr qNameAttrib; + QName objectProviderName; + Element configuration; + XMLObjectBuilder builder; + Marshaller marshaller; + Unmarshaller unmarshaller; + + NodeList providerList = objectProviders.getElementsByTagNameNS(XMLConstants.XMLTOOLING_CONFIG_NS, + "ObjectProvider"); + for (int i = 0; i < providerList.getLength(); i++) { + objectProvider = (Element) providerList.item(i); + + // Get the element name of type this object provider is for + qNameAttrib = objectProvider.getAttributeNodeNS(null, "qualifiedName"); + objectProviderName = XMLHelper.getAttributeValueAsQName(qNameAttrib); + + log.debug("Initializing object provider {}", objectProviderName); + + try { + configuration = (Element) objectProvider.getElementsByTagNameNS(XMLConstants.XMLTOOLING_CONFIG_NS, + "BuilderClass").item(0); + builder = (XMLObjectBuilder) createClassInstance(configuration); + + configuration = (Element) objectProvider.getElementsByTagNameNS(XMLConstants.XMLTOOLING_CONFIG_NS, + "MarshallingClass").item(0); + marshaller = (Marshaller) createClassInstance(configuration); + + configuration = (Element) objectProvider.getElementsByTagNameNS(XMLConstants.XMLTOOLING_CONFIG_NS, + "UnmarshallingClass").item(0); + unmarshaller = (Unmarshaller) createClassInstance(configuration); + + if(retainXMLConfiguration){ + Configuration.registerObjectProvider(objectProviderName, builder, marshaller, unmarshaller, + objectProvider); + }else{ + Configuration.registerObjectProvider(objectProviderName, builder, marshaller, unmarshaller); + } + + log.debug("{} intialized and configuration cached", objectProviderName); + } catch (ConfigurationException e) { + log.error("Error initializing object provier " + objectProvider, e); + // clean up any parts of the object provider that might have been registered before the failure + Configuration.deregisterObjectProvider(objectProviderName); + throw e; + } + } + } + + /** + * Initializes the validator suites specified in the configuration file. + * + * @param validatorSuitesElement the ValidatorSuites element from the configuration file + * + * @throws ConfigurationException thrown if there is a problem initializing the validator suites, usually because of + * malformed elements + */ + protected void initializeValidatorSuites(Element validatorSuitesElement) throws ConfigurationException { + ValidatorSuite validatorSuite; + Validator validator; + Element validatorSuiteElement; + String validatorSuiteId; + Element validatorElement; + QName validatorQName; + + NodeList validatorSuiteList = validatorSuitesElement.getElementsByTagNameNS(XMLConstants.XMLTOOLING_CONFIG_NS, + "ValidatorSuite"); + for (int i = 0; i < validatorSuiteList.getLength(); i++) { + validatorSuiteElement = (Element) validatorSuiteList.item(i); + validatorSuiteId = validatorSuiteElement.getAttributeNS(null, "id"); + validatorSuite = new ValidatorSuite(validatorSuiteId); + + log.debug("Initializing ValidatorSuite {}", validatorSuiteId); + log.trace(XMLHelper.nodeToString(validatorSuiteElement)); + + NodeList validatorList = validatorSuiteElement.getElementsByTagNameNS(XMLConstants.XMLTOOLING_CONFIG_NS, + "Validator"); + for (int j = 0; j < validatorList.getLength(); j++) { + validatorElement = (Element) validatorList.item(j); + validatorQName = XMLHelper.getAttributeValueAsQName(validatorElement.getAttributeNodeNS(null, + "qualifiedName")); + + validator = (Validator) createClassInstance(validatorElement); + validatorSuite.registerValidator(validatorQName, validator); + } + + log.debug("ValidtorSuite {} has been initialized", validatorSuiteId); + if(retainXMLConfiguration){ + Configuration.registerValidatorSuite(validatorSuiteId, validatorSuite, validatorSuiteElement); + }else{ + Configuration.registerValidatorSuite(validatorSuiteId, validatorSuite); + } + } + } + + /** + * Registers the global ID attributes specified in the configuration file. + * + * @param idAttributesElement the IDAttributes element from the configuration file + * + * @throws ConfigurationException thrown if there is a problem with a parsing or registering the the ID attribute + */ + protected void initializeIDAttributes(Element idAttributesElement) throws ConfigurationException { + Element idAttributeElement; + QName attributeQName; + + NodeList idAttributeList = idAttributesElement.getElementsByTagNameNS(XMLConstants.XMLTOOLING_CONFIG_NS, + "IDAttribute"); + + for (int i = 0; i < idAttributeList.getLength(); i++) { + idAttributeElement = (Element) idAttributeList.item(i); + attributeQName = XMLHelper.getElementContentAsQName(idAttributeElement); + if (attributeQName == null) { + log.debug("IDAttribute element was empty, no registration performed"); + } else { + Configuration.registerIDAttribute(attributeQName); + log.debug("IDAttribute {} has been registered", attributeQName); + } + } + } + + /** + * Constructs an instance of the given class. + * + * @param configuration the current configuration element + * + * @return an instance of the given class + * + * @throws ConfigurationException thrown if the class can not be instaniated + */ + protected Object createClassInstance(Element configuration) throws ConfigurationException { + String className = configuration.getAttributeNS(null, "className"); + className = DatatypeHelper.safeTrimOrNullString(className); + + if (className == null) { + return null; + } + + try { + log.trace("Creating instance of {}", className); + ClassLoader classLoader = this.getClass().getClassLoader(); + Class clazz = classLoader.loadClass(className); + Constructor constructor = clazz.getConstructor(); + return constructor.newInstance(); + } catch (Exception e) { + log.error("Can not create instance of " + className, e); + throw new ConfigurationException("Can not create instance of " + className, e); + } + } + + /** + * Schema validates the given configuration. + * + * @param configuration the configuration to validate + * + * @throws ConfigurationException thrown if the configuration is not schema-valid + */ + protected void validateConfiguration(Document configuration) throws ConfigurationException { + try { + javax.xml.validation.Validator schemaValidator = configurationSchema.newValidator(); + schemaValidator.validate(new DOMSource(configuration)); + } catch (IOException e) { + // Should never get here as the DOM is already in memory + String errorMsg = "Unable to read configuration file DOM"; + log.error(errorMsg, e); + throw new ConfigurationException(errorMsg, e); + } catch (SAXException e) { + String errorMsg = "Configuration file does not validate against schema"; + log.error(errorMsg, e); + throw new ConfigurationException(errorMsg, e); + } + } +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/XMLObject.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/XMLObject.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/XMLObject.java 17 Aug 2012 15:17:06 -0000 1.1 @@ -0,0 +1,301 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml; + +import java.util.List; +import java.util.Set; + +import javax.xml.namespace.QName; + +import org.opensaml.xml.schema.XSBooleanValue; +import org.opensaml.xml.util.IDIndex; +import org.w3c.dom.Element; + +/** + * A object that represents an XML element, usually of a specific schema type, that has been unmarshalled into this Java + * object. + */ +public interface XMLObject { + + /** + * Adds a namespace to the ones already scoped to this element. + * + * @deprecated use appropriate methods on the XMLObject's {@link NamespaceManager}. + * + * @param namespace the namespace to add + */ + public void addNamespace(Namespace namespace); + + /** + * Detaches the XMLObject from its parent. This will release the parent's cached DOM (if it has one) and set this + * object's parent to null. It does not remove this object from its parent, that's the responsibility of the invoker + * of this method, nor does it re-root the cached DOM node (if there is one) in a new document. This is handled at + * marshalling time. + */ + public void detach(); + + /** + * Gets the DOM representation of this XMLObject, if one exists. + * + * @return the DOM representation of this XMLObject + */ + public Element getDOM(); + + /** + * Gets the QName for this element. This QName MUST contain the namespace URI, namespace prefix, + * and local element name. Changes made to the returned QName are not reflected by the QName held by this element, + * that is, the returned QName is a copy of the internal QName member of this class. + * + * @return the QName for this attribute + */ + public QName getElementQName(); + + /** + * Get the IDIndex holding the ID-to-XMLObject index mapping, rooted at this XMLObject's subtree. + * + * @return the IDIndex owned by this XMLObject + */ + public IDIndex getIDIndex(); + + /** + * Gets the {@link NamespaceManager} instance for this object. + * + * @return the namespace manager for this object + */ + public NamespaceManager getNamespaceManager(); + + /** + * Gets the namespaces that are scoped to this element. + * + * @return the namespaces that are scoped to this element + */ + public Set getNamespaces(); + + /** + * Gets the value of the XML Schema noNamespaceSchemaLocation attribute for this object. + * + * @return value of the XML Schema noNamespaceSchemaLocation attribute for this object + */ + public String getNoNamespaceSchemaLocation(); + + /** + * Gets an unmodifiable list of child elements in the order that they will appear in the DOM. + * + * @return ordered list of child elements + */ + public List getOrderedChildren(); + + /** + * Gets the parent of this element or null if there is no parent. + * + * @return the parent of this element or null + */ + public XMLObject getParent(); + + /** + * Gets the value of the XML Schema schemaLocation attribute for this object. + * + * @return schema location defined for this object + */ + public String getSchemaLocation(); + + /** + * Gets the XML schema type of this element. This translates to contents the xsi:type attribute for the element. + * + * @return XML schema type of this element + */ + public QName getSchemaType(); + + /** + * Checks if this XMLObject has children. + * + * @return true if this XMLObject has children, false if not + */ + public boolean hasChildren(); + + /** + * Checks to see if this object has a parent. + * + * @return true if the object has a parent, false if not + */ + public boolean hasParent(); + + /** + * Releases the DOM representation of this XMLObject's children. + * + * @param propagateRelease true if all descendants of this element should release their DOM + */ + public void releaseChildrenDOM(boolean propagateRelease); + + /** + * Releases the DOM representation of this XMLObject, if there is one. + */ + public void releaseDOM(); + + /** + * Releases the DOM representation of this XMLObject's parent. + * + * @param propagateRelease true if all ancestors of this element should release their DOM + */ + public void releaseParentDOM(boolean propagateRelease); + + /** + * Removes a namespace from this element. + * + * @deprecated use appropriate methods on the XMLObject's {@link NamespaceManager}. + * + * @param namespace the namespace to remove + */ + public void removeNamespace(Namespace namespace); + + /** + * Find the XMLObject which is identified by the specified ID attribute, within the subtree of XMLObjects which has + * this XMLObject as its root. + * + * @param id the ID attribute to resolve to an XMLObject + * @return the XMLObject identified by the specified ID attribute value + */ + public XMLObject resolveID(String id); + + /** + * Find the XMLObject which is identified by the specified ID attribute, from the root of the tree of XMLObjects in + * which this XMLObject is a member. + * + * @param id the ID attribute to resolve to an XMLObject + * @return the XMLObject identified by the specified ID attribute value + */ + public XMLObject resolveIDFromRoot(String id); + + /** + * Sets the DOM representation of this XMLObject. + * + * @param dom DOM representation of this XMLObject + */ + public void setDOM(Element dom); + + /** + * Sets the value of the XML Schema noNamespaceSchemaLocation attribute for this object. + * + * @param location value of the XML Schema noNamespaceSchemaLocation attribute for this object + */ + public void setNoNamespaceSchemaLocation(String location); + + /** + * Sets the parent of this element. + * + * @param parent the parent of this element + */ + public void setParent(XMLObject parent); + + /** + * Sets the value of the XML Schema schemaLocation attribute for this object. + * + * @param location value of the XML Schema schemaLocation attribute for this object + */ + public void setSchemaLocation(String location); + + /** + * Gets whether the object declares that its element content + * is null, which corresponds to an xsi:nil + * attribute of true. + * + *

+ * Note that it is up to the developer to ensure that the + * value of this attribute is consistent with the actual + * element content on the object instance. + *

+ * + *

+ * Per the XML Schema specification, a value of true disallows + * element content, but not element attributes. + *

+ * + * @see + * + * @return whether the object's content model is null + */ + public Boolean isNil(); + + /** + * + * Gets whether the object declares that its element content + * is null, which corresponds to an xsi:nil + * attribute of true. + * + *

+ * Note that it is up to the developer to ensure that the + * value of this attribute is consistent with the actual + * element content on the object instance. + *

+ * + *

+ * Per the XML Schema specification, a value of true disallows + * element content, but not element attributes. + *

+ * + * @see
+ * + * @param newNil whether the object's content model is expressed as null + */ + public void setNil(Boolean newNil); + + /** + * Sets whether the object declares that its element content + * is null, which corresponds to an xsi:nil + * attribute of true. + * + *

+ * Note that it is up to the developer to ensure that the + * value of this attribute is consistent with the actual + * element content on the object instance. + *

+ * + *

+ * Per the XML Schema specification, a value of true disallows + * element content, but not element attributes. + *

+ * + * @see
the XMLObject type that this builder produces + */ +public interface XMLObjectBuilder { + + /** + * Creates an XMLObject with a given fully qualified name. + * + * @param objectName fully qualified name of the object + * + * @return the constructed XMLObject + */ + public XMLObjectType buildObject(QName objectName); + + /** + * Creates an XMLObject with a given fully qualified name and schema type. + * + * @param objectName fully qualified name of the object + * @param schemaType the schema type of the Element represented by this XMLObject + * + * @return the constructed XMLObject + */ + public XMLObjectType buildObject(QName objectName, QName schemaType); + + /** + * Creates an XMLObject with a given fully qualified name. + * + * @param namespaceURI the URI of the namespace the Element represented by this XMLObject will be in + * @param localName the local name of the Element represented by this XMLObject + * @param namespacePrefix the namespace prefix of the Element represented by this XMLObject + * + * @return the constructed XMLObject + */ + public XMLObjectType buildObject(String namespaceURI, String localName, String namespacePrefix); + + /** + * Creates an XMLObject with a given fully qualified name. + * + * @param namespaceURI the URI of the namespace the Element represented by this XMLObject will be in + * @param localName the local name of the Element represented by this XMLObject + * @param namespacePrefix the namespace prefix of the Element represented by this XMLObject + * @param schemaType the schema type of the Element represented by this XMLObject + * + * @return the constructed XMLObject + */ + public XMLObjectType buildObject(String namespaceURI, String localName, String namespacePrefix, QName schemaType); + + /** + * Creates an XMLObject using information from the given DOM element. This method must set the QName for the Element + * QName within the constructed XMLObject. + * + * This method is used by {@link org.opensaml.xml.io.AbstractXMLObjectUnmarshaller}. + * + * @param element the DOM Element containing information about the object to be built. + * + * @return the constructed XMLObject + */ + public XMLObjectType buildObject(Element element); +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/XMLObjectBuilderFactory.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/XMLObjectBuilderFactory.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/XMLObjectBuilderFactory.java 17 Aug 2012 15:17:06 -0000 1.1 @@ -0,0 +1,121 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml; + +import java.util.Collections; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import javax.xml.namespace.QName; + +import org.opensaml.xml.util.XMLHelper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.w3c.dom.Element; + +/** + * A factory for {@link org.opensaml.xml.XMLObjectBuilder}s. XMLObjectBuilders are stored and retrieved by a + * {@link javax.xml.namespace.QName} key. This key is either the XML Schema Type or element QName of the XML element the + * built XMLObject object represents. + */ +public class XMLObjectBuilderFactory { + + /** Class logger. */ + private final Logger log = LoggerFactory.getLogger(XMLObjectBuilderFactory.class); + + /** Registered builders. */ + private Map builders; + + /** Constructor. */ + public XMLObjectBuilderFactory() { + builders = new ConcurrentHashMap(); + } + + /** + * Retrieves an {@link XMLObjectBuilder} using the key it was registered with. + * + * @param key the key used to register the builder + * + * @return the builder + */ + public XMLObjectBuilder getBuilder(QName key) { + if(key == null){ + return null; + } + return builders.get(key); + } + + /** + * Retrieves the XMLObject builder for the given element. The schema type, if present, is tried first as the key + * with the element QName used if no schema type is present or does not have a builder registered under it. + * + * @param domElement the element to retrieve the builder for + * + * @return the builder for the XMLObject the given element can be unmarshalled into + */ + public XMLObjectBuilder getBuilder(Element domElement) { + XMLObjectBuilder builder; + + builder = getBuilder(XMLHelper.getXSIType(domElement)); + + if (builder == null) { + builder = getBuilder(XMLHelper.getNodeQName(domElement)); + } + + return builder; + } + + /** + * Gets an immutable list of all the builders currently registered. + * + * @return list of all the builders currently registered + */ + public Map getBuilders() { + return Collections.unmodifiableMap(builders); + } + + /** + * Registers a new builder for the given name. + * + * @param builderKey the key used to retrieve this builder later + * @param builder the builder + */ + public void registerBuilder(QName builderKey, XMLObjectBuilder builder) { + log.debug("Registering builder, {} under key {}", builder.getClass().getName(), builderKey); + if(builderKey == null){ + throw new IllegalArgumentException("Builder key may not be null"); + } + builders.put(builderKey, builder); + } + + /** + * Deregisters a builder. + * + * @param builderKey the key for the builder to be deregistered + * + * @return the builder that was registered for the given QName + */ + public XMLObjectBuilder deregisterBuilder(QName builderKey) { + log.debug("Deregistering builder for object type {}", builderKey); + if(builderKey != null){ + return builders.remove(builderKey); + } + + return null; + } +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/XMLRuntimeException.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/XMLRuntimeException.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/XMLRuntimeException.java 17 Aug 2012 15:17:07 -0000 1.1 @@ -0,0 +1,62 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml; + +/** + * An unchecked runtime exception thrown when an unrecoverable error occurs during XML processing. + */ +public class XMLRuntimeException extends RuntimeException { + + /** Serial version UID. */ + private static final long serialVersionUID = 1299468635977382060L; + + /** + * Constructor. + */ + public XMLRuntimeException() { + super(); + } + + /** + * Constructor. + * + * @param message exception message + */ + public XMLRuntimeException(String message) { + super(message); + } + + /** + * Constructor. + * + * @param wrappedException exception to be wrapped by this one + */ + public XMLRuntimeException(Exception wrappedException) { + super(wrappedException); + } + + /** + * Constructor. + * + * @param message exception message + * @param wrappedException exception to be wrapped by this one + */ + public XMLRuntimeException(String message, Exception wrappedException) { + super(message, wrappedException); + } +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/package.html =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/package.html,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/package.html 17 Aug 2012 15:17:07 -0000 1.1 @@ -0,0 +1,12 @@ + + +Base classes for working with XML as Java objects and configuring the library. + +

+The Configuration class provides the mechanism for loading configuration files +and fetching configured builder, marshaller, and unmarshaller factories. +

+The ElementProxy classes can be used as the default XMLObject for DOM content that +does not have registed object providers. + + \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/AbstractEncryptedKeyResolver.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/AbstractEncryptedKeyResolver.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/AbstractEncryptedKeyResolver.java 17 Aug 2012 15:16:58 -0000 1.1 @@ -0,0 +1,116 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption; + +import java.util.ArrayList; +import java.util.List; + +import org.opensaml.xml.security.keyinfo.KeyInfoHelper; +import org.opensaml.xml.util.DatatypeHelper; + +/** + * Abstract class implementation for {@link EncryptedKeyResolver}. + */ +public abstract class AbstractEncryptedKeyResolver implements EncryptedKeyResolver { + + /** Recipient attribute criteria against which to match.*/ + private final List recipients; + + /** Constructor. */ + public AbstractEncryptedKeyResolver() { + recipients = new ArrayList(); + } + + /** {@inheritDoc} */ + public List getRecipients() { + return recipients; + } + + /** + * Evaluate whether the specified recipient attribute value matches this resolver's + * recipient criteria. + * + * @param recipient the recipient value to evaluate + * @return true if the recipient value matches the resolver's criteria, false otherwise + */ + protected boolean matchRecipient(String recipient) { + String trimmedRecipient = DatatypeHelper.safeTrimOrNullString(recipient); + if (trimmedRecipient == null || recipients.isEmpty()) { + return true; + } + + return recipients.contains(trimmedRecipient); + } + + /** + * Evaluate whether an EncryptedKey's CarriedKeyName matches one of the KeyName values + * from the EncryptedData context. + * + * @param encryptedData the EncryptedData context + * @param encryptedKey the candidate Encryptedkey to evaluate + * @return true if the encrypted key's carried key name matches that of the encrytped data, + * false otherwise + */ + protected boolean matchCarriedKeyName(EncryptedData encryptedData, EncryptedKey encryptedKey) { + if (encryptedKey.getCarriedKeyName() == null + || DatatypeHelper.isEmpty(encryptedKey.getCarriedKeyName().getValue()) ) { + return true; + } + + if (encryptedData.getKeyInfo() == null + || encryptedData.getKeyInfo().getKeyNames().isEmpty() ) { + return false; + } + + String keyCarriedKeyName = encryptedKey.getCarriedKeyName().getValue(); + List dataKeyNames = KeyInfoHelper.getKeyNames(encryptedData.getKeyInfo()); + + return dataKeyNames.contains(keyCarriedKeyName); + } + + /** + * Evaluate whether any of the EncryptedKey's DataReferences refer to the EncryptedData + * context. + * + * @param encryptedData the EncryptedData context + * @param encryptedKey the candidate Encryptedkey to evaluate + * @return true if any of the encrypted key's data references refer to the encrypted data context, + * false otherwise + */ + protected boolean matchDataReference(EncryptedData encryptedData, EncryptedKey encryptedKey) { + if (encryptedKey.getReferenceList() == null + || encryptedKey.getReferenceList().getDataReferences().isEmpty() ) { + return true; + } + + if (DatatypeHelper.isEmpty(encryptedData.getID())) { + return false; + } + + List drlist = encryptedKey.getReferenceList().getDataReferences(); + for (DataReference dr : drlist) { + if (DatatypeHelper.isEmpty(dr.getURI()) || ! dr.getURI().startsWith("#") ) { + continue; + } + if (dr.resolveIDFromRoot(dr.getURI().substring(1)) == encryptedData) { + return true; + } + } + return false; + } +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/AgreementMethod.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/AgreementMethod.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/AgreementMethod.java 17 Aug 2012 15:16:58 -0000 1.1 @@ -0,0 +1,104 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption; + +import javax.xml.namespace.QName; + +import org.opensaml.xml.ElementExtensibleXMLObject; +import org.opensaml.xml.util.XMLConstants; +import org.opensaml.xml.validation.ValidatingXMLObject; + +/** + * XMLObject representing XML Encryption, version 20021210, AgreementMethod element. + */ +public interface AgreementMethod extends ValidatingXMLObject, ElementExtensibleXMLObject { + + /** Element local name. */ + public static final String DEFAULT_ELEMENT_LOCAL_NAME = "AgreementMethod"; + + /** Default element name. */ + public static final QName DEFAULT_ELEMENT_NAME = new QName(XMLConstants.XMLENC_NS, DEFAULT_ELEMENT_LOCAL_NAME, + XMLConstants.XMLENC_PREFIX); + + /** Local name of the XSI type. */ + public static final String TYPE_LOCAL_NAME = "AgreementMethodType"; + + /** QName of the XSI type. */ + public static final QName TYPE_NAME = new QName(XMLConstants.XMLENC_NS, TYPE_LOCAL_NAME, + XMLConstants.XMLENC_PREFIX); + + /** Algorithm attribute name. */ + public static final String ALGORITHM_ATTRIBUTE_NAME = "Algorithm"; + + /** + * Gets the algorithm URI attribute value for this agreement method. + * + * @return the algorithm URI attribute value + */ + public String getAlgorithm(); + + /** + * Sets the algorithm URI attribute value for this agreement method. + * + * @param newAlgorithm the new algorithm URI attribute value + */ + public void setAlgorithm(String newAlgorithm); + + /** + * Get the nonce child element used to introduce variability into the generation of keying material. + * + * @return the KA-Nonce child element + */ + public KANonce getKANonce(); + + /** + * Set the nonce child element used to introduce variability into the generation of keying material. + * + * @param newKANonce the new KA-Nonce child element + */ + public void setKANonce(KANonce newKANonce); + + /** + * Get the child element containing the key generation material for the originator. + * + * @return the OriginatorKeyInfo child element + */ + public OriginatorKeyInfo getOriginatorKeyInfo(); + + /** + * Set the child element containing the key generation material for the originator. + * + * @param newOriginatorKeyInfo the new OriginatorKeyInfo child element + */ + public void setOriginatorKeyInfo(OriginatorKeyInfo newOriginatorKeyInfo); + + /** + * Get the child element containing the key generation material for the recipient. + * + * @return the RecipientKeyInfo child element + */ + public RecipientKeyInfo getRecipientKeyInfo(); + + /** + * Set the child element containing the key generation material for the recipient. + * + * @param newRecipientKeyInfo the new RecipientKeyInfo child element + */ + public void setRecipientKeyInfo(RecipientKeyInfo newRecipientKeyInfo); + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/CarriedKeyName.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/CarriedKeyName.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/CarriedKeyName.java 17 Aug 2012 15:16:59 -0000 1.1 @@ -0,0 +1,37 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption; + +import javax.xml.namespace.QName; + +import org.opensaml.xml.schema.XSString; +import org.opensaml.xml.util.XMLConstants; + +/** + * XMLObject representing XML Encryption, version 20021210, CarriedKeyName element. + */ +public interface CarriedKeyName extends XSString { + + /** Element local name. */ + public static final String DEFAULT_ELEMENT_LOCAL_NAME = "CarriedKeyName"; + + /** Default element name. */ + public static final QName DEFAULT_ELEMENT_NAME = new QName(XMLConstants.XMLENC_NS, DEFAULT_ELEMENT_LOCAL_NAME, + XMLConstants.XMLENC_PREFIX); + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/ChainingEncryptedKeyResolver.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/ChainingEncryptedKeyResolver.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/ChainingEncryptedKeyResolver.java 17 Aug 2012 15:16:59 -0000 1.1 @@ -0,0 +1,218 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.NoSuchElementException; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * An implementation of {@link EncryptedKeyResolver} which chains multiple other resolver implementations together, + * calling them in the order specified in the resolver list. + */ +public class ChainingEncryptedKeyResolver extends AbstractEncryptedKeyResolver { + + /** The list of resolvers which form the resolution chain. */ + private final List resolvers; + + /** Class logger. */ + private final Logger log = LoggerFactory.getLogger(ChainingEncryptedKeyResolver.class); + + /** Constructor. */ + public ChainingEncryptedKeyResolver() { + resolvers = new ArrayList(); + } + + /** + * Get the list of resolvers which form the resolution chain. + * + * @return a list of EncryptedKeyResolver instances + */ + public List getResolverChain() { + return resolvers; + } + + /** {@inheritDoc} */ + public Iterable resolve(EncryptedData encryptedData) { + if (resolvers.isEmpty()) { + log.warn("Chaining encrypted key resolver resolution was attempted with an empty resolver chain"); + throw new IllegalStateException("The resolver chain is empty"); + } + return new ChainingIterable(this, encryptedData); + } + + /** + * Implementation of {@link Iterable} to be returned by {@link ChainingEncryptedKeyResolver}. + */ + public class ChainingIterable implements Iterable { + + /** The chaining encrypted key resolver which owns this instance. */ + private ChainingEncryptedKeyResolver parent; + + /** The EncryptedData context for resolution. */ + private EncryptedData encryptedData; + + /** + * Constructor. + * + * @param resolver the ChainingEncryptedKeyResolver parent + * @param encData the EncryptedData context for resolution + */ + public ChainingIterable(ChainingEncryptedKeyResolver resolver, EncryptedData encData) { + parent = resolver; + encryptedData = encData; + } + + /** {@inheritDoc} */ + public Iterator iterator() { + return new ChainingIterator(parent, encryptedData); + } + + } + + /** + * Implementation of {@link Iterator} to be (indirectly) returned by {@link ChainingEncryptedKeyResolver}. + * + */ + public class ChainingIterator implements Iterator { + + /** Class logger. */ + private final Logger log = LoggerFactory.getLogger(ChainingEncryptedKeyResolver.ChainingIterator.class); + + /** The chaining encrypted key resolver which owns this instance. */ + private ChainingEncryptedKeyResolver parent; + + /** The EncryptedData context for resolution. */ + private EncryptedData encryptedData; + + /** The iterator over resolvers in the chain. */ + private Iterator resolverIterator; + + /** The iterator over EncryptedKey instances from the current resolver. */ + private Iterator keyIterator; + + /** The current resolver which is returning encrypted keys. */ + private EncryptedKeyResolver currentResolver; + + /** The next encrypted key that is safe to return. */ + private EncryptedKey nextKey; + + /** + * Constructor. + * + * @param resolver the ChainingEncryptedKeyResolver parent + * @param encData the EncryptedData context for resolution + */ + public ChainingIterator(ChainingEncryptedKeyResolver resolver, EncryptedData encData) { + parent = resolver; + encryptedData = encData; + resolverIterator = parent.getResolverChain().iterator(); + keyIterator = getNextKeyIterator(); + nextKey = null; + } + + /** {@inheritDoc} */ + public boolean hasNext() { + if (nextKey != null) { + return true; + } + nextKey = getNextKey(); + if (nextKey != null) { + return true; + } + return false; + } + + /** {@inheritDoc} */ + public EncryptedKey next() { + EncryptedKey tempKey; + if (nextKey != null) { + tempKey = nextKey; + nextKey = null; + return tempKey; + } + tempKey = getNextKey(); + if (tempKey != null) { + return tempKey; + } else { + throw new NoSuchElementException("No more EncryptedKey elements are available"); + } + } + + /** {@inheritDoc} */ + public void remove() { + throw new UnsupportedOperationException("Remove operation is not supported by this iterator"); + } + + /** + * Get the iterator from the next resolver in the chain. + * + * @return an iterator of encrypted keys + */ + private Iterator getNextKeyIterator() { + if (resolverIterator.hasNext()) { + currentResolver = resolverIterator.next(); + log.debug("Getting key iterator from next resolver: {}", currentResolver.getClass().toString()); + return currentResolver.resolve(encryptedData).iterator(); + } else { + log.debug("No more resolvers available in the resolver chain"); + currentResolver = null; + return null; + } + } + + /** + * Get the next encrypted key that will be returned by this iterator. + * + * @return the next encrypted key to return + */ + private EncryptedKey getNextKey() { + EncryptedKey tempKey; + + if (keyIterator != null) { + while (keyIterator.hasNext()) { + tempKey = keyIterator.next(); + if (parent.matchRecipient(tempKey.getRecipient())) { + log.debug("Found matching encrypted key: {}", tempKey.toString()); + return tempKey; + } + } + } + + keyIterator = getNextKeyIterator(); + while (keyIterator != null) { + while (keyIterator.hasNext()) { + tempKey = keyIterator.next(); + if (parent.matchRecipient(tempKey.getRecipient())) { + log.debug("Found matching encrypted key: {}", tempKey.toString()); + return tempKey; + } + } + keyIterator = getNextKeyIterator(); + } + + return null; + } + + } + +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/CipherData.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/CipherData.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/CipherData.java 17 Aug 2012 15:16:59 -0000 1.1 @@ -0,0 +1,71 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption; + +import javax.xml.namespace.QName; + +import org.opensaml.xml.util.XMLConstants; +import org.opensaml.xml.validation.ValidatingXMLObject; + +/** + * XMLObject representing XML Encryption, version 20021210, CipherData element. + */ +public interface CipherData extends ValidatingXMLObject { + + /** Element local name. */ + public static final String DEFAULT_ELEMENT_LOCAL_NAME = "CipherData"; + + /** Default element name. */ + public static final QName DEFAULT_ELEMENT_NAME = new QName(XMLConstants.XMLENC_NS, DEFAULT_ELEMENT_LOCAL_NAME, + XMLConstants.XMLENC_PREFIX); + + /** Local name of the XSI type. */ + public static final String TYPE_LOCAL_NAME = "CipherDataType"; + + /** QName of the XSI type. */ + public static final QName TYPE_NAME = new QName(XMLConstants.XMLENC_NS, TYPE_LOCAL_NAME, + XMLConstants.XMLENC_PREFIX); + + /** + * Get the base64-encoded data representing the the encrypted form of the plaintext data. + * + * @return base64-encoded encrypted value + */ + public CipherValue getCipherValue(); + + /** + * Set the base64-encoded data representing the the encrypted form of the plaintext data. + * + * @param newCipherValue the new base64-encoded encrypted data + */ + public void setCipherValue(CipherValue newCipherValue); + + /** + * Get the CipherReference which points to the location encrypted data. + * + * @return CipherReference child element representing the encrypted data + */ + public CipherReference getCipherReference(); + + /** + * Get the CipherReference which points to the location encrypted data. + * + * @param newCipherReference the new CipherReference child element + */ + public void setCipherReference(CipherReference newCipherReference); +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/CipherReference.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/CipherReference.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/CipherReference.java 17 Aug 2012 15:16:59 -0000 1.1 @@ -0,0 +1,75 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption; + +import javax.xml.namespace.QName; + +import org.opensaml.xml.util.XMLConstants; +import org.opensaml.xml.validation.ValidatingXMLObject; + +/** + * XMLObject representing XML Encryption, version 20021210, CipherReference element. + */ +public interface CipherReference extends ValidatingXMLObject { + + /** Element local name. */ + public static final String DEFAULT_ELEMENT_LOCAL_NAME = "CipherReference"; + + /** Default element name. */ + public static final QName DEFAULT_ELEMENT_NAME = new QName(XMLConstants.XMLENC_NS, DEFAULT_ELEMENT_LOCAL_NAME, + XMLConstants.XMLENC_PREFIX); + + /** Local name of the XSI type. */ + public static final String TYPE_LOCAL_NAME = "CipherReferenceType"; + + /** QName of the XSI type. */ + public static final QName TYPE_NAME = new QName(XMLConstants.XMLENC_NS, TYPE_LOCAL_NAME, + XMLConstants.XMLENC_PREFIX); + + /** URI attribute name. */ + public static final String URI_ATTRIB_NAME = "URI"; + + /** + * Get the URI attribute that describes from where to deference the encrypted data. + * + * @return the URI attribute string + */ + public String getURI(); + + /** + * Set the URI attribute that describes from where to deference the encrypted data. + * + * @param newURI the new URI attribute string value + */ + public void setURI(String newURI); + + /** + * Get the Transforms child element, which describes which transformations to apply when dereferencing the data. + * + * @return the Transforms child element + */ + public Transforms getTransforms(); + + /** + * Set the Transforms child element, which describes which transformations to apply when dereferencing the data. + * + * @param newTransforms the new Transforms child element + */ + public void setTransforms(Transforms newTransforms); + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/CipherValue.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/CipherValue.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/CipherValue.java 17 Aug 2012 15:16:59 -0000 1.1 @@ -0,0 +1,37 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption; + +import javax.xml.namespace.QName; + +import org.opensaml.xml.schema.XSBase64Binary; +import org.opensaml.xml.util.XMLConstants; + +/** + * XMLObject representing XML Encryption, version 20021210, CipherValue element. + */ +public interface CipherValue extends XSBase64Binary { + + /** Element local name. */ + public static final String DEFAULT_ELEMENT_LOCAL_NAME = "CipherValue"; + + /** Default element name. */ + public static final QName DEFAULT_ELEMENT_NAME = new QName(XMLConstants.XMLENC_NS, DEFAULT_ELEMENT_LOCAL_NAME, + XMLConstants.XMLENC_PREFIX); + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/DHKeyValue.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/DHKeyValue.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/DHKeyValue.java 17 Aug 2012 15:16:58 -0000 1.1 @@ -0,0 +1,128 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption; + +import javax.xml.namespace.QName; + +import org.opensaml.xml.util.XMLConstants; +import org.opensaml.xml.validation.ValidatingXMLObject; + +/** + * XMLObject representing XML Encryption, version 20021210, DHKeyValue element. + */ +public interface DHKeyValue extends ValidatingXMLObject { + + /** Element local name. */ + public static final String DEFAULT_ELEMENT_LOCAL_NAME = "DHKeyValue"; + + /** Default element name. */ + public final QName DEFAULT_ELEMENT_NAME = new QName(XMLConstants.XMLENC_NS, DEFAULT_ELEMENT_LOCAL_NAME, + XMLConstants.XMLENC_PREFIX); + + /** Local name of the XSI type. */ + public static final String TYPE_LOCAL_NAME = "DHKeyValueType"; + + /** QName of the XSI type. */ + public static final QName TYPE_NAME = new QName(XMLConstants.XMLENC_NS, TYPE_LOCAL_NAME, + XMLConstants.XMLENC_PREFIX); + + /** + * Get the P child element. + * + * @return the P child element + */ + public P getP(); + + /** + * Set the P child element. + * + * @param newP the new P child element + */ + public void setP(P newP); + + /** + * Get the Q child element. + * + * @return the Q child element + */ + public Q getQ(); + + /** + * Set the Q child element. + * + * @param newQ the new Q child element + */ + public void setQ(Q newQ); + + /** + * Get the Generator child element. + * + * @return the Generator child element + */ + public Generator getGenerator(); + + /** + * Set the G child element. + * + * @param newGenerator the new G child element + */ + public void setGenerator(Generator newGenerator); + + /** + * Get the Public element. + * + * @return the Public element + */ + public Public getPublic(); + + /** + * Set the Public element. + * + * @param newPublic the new Public child element + */ + public void setPublic(Public newPublic); + + /** + * Get the seed element. + * + * @return the seed element + */ + public Seed getSeed(); + + /** + * Set the seed element. + * + * @param newSeed new seed element + */ + public void setSeed(Seed newSeed); + + /** + * Get the pgenCounter element. + * + * @return the pgenCounter element + */ + public PgenCounter getPgenCounter(); + + /** + * Set the pgenCounter element. + * + * @param newPgenCounter new pgenCounter element + */ + public void setPgenCounter(PgenCounter newPgenCounter); + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/DataReference.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/DataReference.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/DataReference.java 17 Aug 2012 15:16:58 -0000 1.1 @@ -0,0 +1,36 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption; + +import javax.xml.namespace.QName; + +import org.opensaml.xml.util.XMLConstants; + +/** + * XMLObject representing XML Encryption, version 20021210, DataReference element. + */ +public interface DataReference extends ReferenceType { + + /** Element local name. */ + public static final String DEFAULT_ELEMENT_LOCAL_NAME = "DataReference"; + + /** Default element name. */ + public static final QName DEFAULT_ELEMENT_NAME = new QName(XMLConstants.XMLENC_NS, DEFAULT_ELEMENT_LOCAL_NAME, + XMLConstants.XMLENC_PREFIX); + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/Decrypter.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/Decrypter.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/Decrypter.java 17 Aug 2012 15:16:58 -0000 1.1 @@ -0,0 +1,990 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.security.Key; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; + +import org.apache.xml.security.Init; +import org.apache.xml.security.encryption.XMLCipher; +import org.apache.xml.security.encryption.XMLEncryptionException; +import org.opensaml.xml.Configuration; +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.io.Marshaller; +import org.opensaml.xml.io.MarshallingException; +import org.opensaml.xml.io.UnmarshallerFactory; +import org.opensaml.xml.io.UnmarshallingException; +import org.opensaml.xml.parse.BasicParserPool; +import org.opensaml.xml.parse.XMLParserException; +import org.opensaml.xml.security.Criteria; +import org.opensaml.xml.security.CriteriaSet; +import org.opensaml.xml.security.SecurityException; +import org.opensaml.xml.security.SecurityHelper; +import org.opensaml.xml.security.credential.Credential; +import org.opensaml.xml.security.credential.UsageType; +import org.opensaml.xml.security.criteria.KeyAlgorithmCriteria; +import org.opensaml.xml.security.criteria.KeyLengthCriteria; +import org.opensaml.xml.security.criteria.UsageCriteria; +import org.opensaml.xml.security.keyinfo.KeyInfoCredentialResolver; +import org.opensaml.xml.security.keyinfo.KeyInfoCriteria; +import org.opensaml.xml.signature.DigestMethod; +import org.opensaml.xml.signature.SignatureConstants; +import org.opensaml.xml.util.DatatypeHelper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.w3c.dom.Document; +import org.w3c.dom.DocumentFragment; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +/** + * Supports decryption of XMLObjects which represent data encrypted according to the XML Encryption specification, + * version 20021210. + * + *

+ * Details on the components specified as constructor options are as follows: + *

    + * + *
  1. + * newResolver: This {@link KeyInfoCredentialResolver} instance is used to resolve keys (as Credentials) + * based on the KeyInfo of EncryptedData elements. While it could in theory be used to handle the complete process of + * resolving the data decryption key, including decrypting any necessary EncryptedKey's, it would typically + * be used in cases where encrypted key transport via an EncryptedKey is not being employed. + * This corresponds to scenarios where decryption is instead based on resolving the (presumably shared secret) + * symmetric data decryption key directly, based on either context or information present in the + * EncryptedData's KeyInfo. In cases where the data decryption key is to be resolved by decrypting an EncryptedKey, + * this resolver would typically not be used and may be null. + *
  2. + * + *
  3. + * newKEKResolver: This {@link KeyInfoCredentialResolver} instance is used to resolve keys (as Credentials) + * used to decrypt EncryptedKey elements, based on the KeyInfo information contained within the EncryptedKey element + * (also known as a Key Encryption Key or KEK). For asymmetric key transport of encrypted keys, this would entail + * resolving the private key which corresponds to the public key which was used to encrypt the EncryptedKey. + *
  4. + * + *
  5. + * newEncKeyResolver: This {@link EncryptedKeyResolver} instance is responsible for resolving + * the EncryptedKey element(s) which hold(s) the encrypted data decryption key which would be used to + * decrypt an EncryptedData element. + *
  6. + * + *
+ *

+ * + *

+ * XML Encryption can encrypt either a single {@link Element} or the contents of an Element. The caller of this class + * must select the decryption method which is most appropriate for their specific use case. + *

+ * + *

+ * Note that the type of plaintext data contained by an {@link EncryptedData} can be checked prior to decryption by + * examining that element's type attribute ({@link EncryptedData#getType}). This (optional) attribute + * may contain one of the following two constant values to aid in the decryption process: + * {@link EncryptionConstants#TYPE_ELEMENT} or {@link EncryptionConstants#TYPE_CONTENT}. + *

+ * + *

+ * By nature the fundamental output of XML decryption is a DOM {@link DocumentFragment} with 1 or more immediate + * top-level DOM {@link Node} children. This case is reflected in the method {@link #decryptDataToDOM(EncryptedData)}. + * It is up to the caller to properly process the DOM Nodes which are the children of this document fragment. The + * DocumentFragment and its Node children will be owned by the DOM {@link Document} which owned the original + * EncryptedData before decryption. Note, however, that the Node children will not be a part of the tree of Nodes rooted + * at that Document's document element. + *

+ * + *

+ * A typical use case will be that the content which was encrypted contained solely {@link Element} nodes. For this use + * case a convenience method is provided as {@link #decryptDataToList(EncryptedData)}, which returns a list of + * {@link XMLObject}'s which are the result of unmarshalling each of the child Elements of the decrypted + * DocumentFragment. + *

+ * + *

+ * Another typical use case is that the content which was encrypted was a single Element. For this use case a + * convenience method is provided as {@link #decryptData(EncryptedData)}, which returns a single XMLObject which was + * the result of unmarshalling this decrypted Element. + *

+ * + *

+ * In both of these cases the underlying DOM Element which is represented by each of the returned XMLObjects will be + * owned by the DOM Document which also owns the original EncrytpedData Element. However, note that these cached DOM + * Elements are not part of the tree of Nodes rooted at that Document's document element. If these + * returned XMLObjects are then inserted as the children of other XMLObjects, it is up to the caller to ensure that the + * XMLObject tree is then remarshalled if the relationship of the cached DOM nodes is important (e.g. resolution of + * ID-typed attributes via {@link Document#getElementById(String)}). + *

+ * + *

+ * For some use cases where the returned XMLObjects will not necessarily be stored back as children of another parent + * XMLObject, it may still necessary for the DOM Elements of the resultant XMLObjects to exist within the tree of Nodes + * rooted at a DOM Document's document element (e.g. signature verification on the standalone decrypted XMLObject). For + * these cases these method variants may be used: {@link #decryptDataToList(EncryptedData, boolean)} and + * {@link #decryptData(EncryptedData, boolean)}. The rootInNewDocument parameter is explained below. + * A default value for this parameter, for the overloaded convenience methods + * which do not take this parameter explicitly, may be set via {@link #setRootInNewDocument(boolean)}. + * This default value is initialized to false. + *

+ * + *

If the boolean option rootInNewDocument is true at the time of decryption, + * then for each top-level child Element of the decrypted DocumentFragment, the following will occur: + * + *

    + *
  1. A new DOM Document will be created.
  2. + *
  3. The Element will be adopted into that Document.
  4. + *
  5. The Element will be made the root element of the Document.
  6. + *
  7. The Element will be unmarshalled into an XMLObject as in the single argument variant.
  8. + *
+ * + *

+ * Note that new Document creation, node adoption and rooting the new document element are potentially very expensive. + * This should only be done where the caller's use case really requires it. + *

+ * + */ +public class Decrypter { + + /** ParserPool used in parsing decrypted data. */ + private final BasicParserPool parserPool; + + /** Unmarshaller factory, used in decryption of EncryptedData objects. */ + private UnmarshallerFactory unmarshallerFactory; + + /** Load-and-Save DOM Implementation singleton. */ + // private DOMImplementationLS domImplLS; + /** Class logger. */ + private final Logger log = LoggerFactory.getLogger(Decrypter.class); + + /** Resolver for data encryption keys. */ + private KeyInfoCredentialResolver resolver; + + /** Resolver for key encryption keys. */ + private KeyInfoCredentialResolver kekResolver; + + /** Resolver for EncryptedKey instances which contain the encrypted data encryption key. */ + private EncryptedKeyResolver encKeyResolver; + + /** Additional criteria to use when resolving credentials based on an EncryptedData's KeyInfo. */ + private CriteriaSet resolverCriteria; + + /** Additional criteria to use when resolving credentials based on an EncryptedKey's KeyInfo. */ + private CriteriaSet kekResolverCriteria; + + /** The name of the JCA security provider to use. */ + private String jcaProviderName; + + /** Flag to determine whether by default the Element which backs the underlying decrypted SAMLObject will be the + * root of a new DOM document. */ + private boolean defaultRootInNewDocument; + + + /** + * Constructor. + * + * @param newResolver resolver for data encryption keys. + * @param newKEKResolver resolver for key encryption keys. + * @param newEncKeyResolver resolver for EncryptedKey elements + */ + public Decrypter(KeyInfoCredentialResolver newResolver, KeyInfoCredentialResolver newKEKResolver, + EncryptedKeyResolver newEncKeyResolver) { + resolver = newResolver; + kekResolver = newKEKResolver; + encKeyResolver = newEncKeyResolver; + + resolverCriteria = null; + kekResolverCriteria = null; + + // Note: this is hopefully only temporary, until Xerces implements DOM 3 LSParser.parseWithContext(). + parserPool = new BasicParserPool(); + parserPool.setNamespaceAware(true); + + // Note: this is necessary due to an unresolved Xerces deferred DOM issue/bug + HashMap features = new HashMap(); + features.put("http://apache.org/xml/features/dom/defer-node-expansion", Boolean.FALSE); + parserPool.setBuilderFeatures(features); + + unmarshallerFactory = Configuration.getUnmarshallerFactory(); + + defaultRootInNewDocument = false; + } + + /** + * Get the flag which indicates whether by default the DOM Element which backs a decrypted SAML object + * will be the root of a new DOM document. Defaults to false. + * + * @return the current value of the flag for this decrypter instance + */ + public boolean isRootInNewDocument() { + return defaultRootInNewDocument; + } + + /** + * Set the flag which indicates whether by default the DOM Element which backs a decrypted SAML object + * will be the root of a new DOM document. Defaults to false. + * + * @param flag the current value of the flag for this decrypter instance + */ + public void setRootInNewDocument(boolean flag) { + defaultRootInNewDocument = flag; + } + + /** + * Get the Java Cryptography Architecture (JCA) security provider name that should be used to provide the decryption + * support. + * + * Defaults to null, which means that the first registered provider which supports the indicated + * encryption algorithm URI will be used. + * + * @return the JCA provider name to use + */ + public String getJCAProviderName() { + return jcaProviderName; + } + + /** + * Set the Java Cryptography Architecture (JCA) security provider name that should be used to provide the decryption + * support. + * + * Defaults to null, which means that the first registered provider which supports the indicated + * encryption algorithm URI will be used. + * + * @param providerName the JCA provider name to use + */ + public void setJCAProviderName(String providerName) { + jcaProviderName = providerName; + } + + /** + * Get the data encryption key credential resolver. + * + * @return the data encryption key resolver + */ + public KeyInfoCredentialResolver getKeyResolver() { + return resolver; + } + + /** + * Set a new data encryption key credential resolver. + * + * @param newResolver the new data encryption key resolver + */ + public void setKeyResolver(KeyInfoCredentialResolver newResolver) { + resolver = newResolver; + } + + /** + * Get the key encryption key credential resolver. + * + * @return the key encryption key resolver + */ + public KeyInfoCredentialResolver getKEKResolver() { + return kekResolver; + } + + /** + * Set a new key encryption key credential resolver. + * + * @param newKEKResolver the new key encryption key resolver + */ + public void setKEKResolver(KeyInfoCredentialResolver newKEKResolver) { + kekResolver = newKEKResolver; + } + + /** + * Get the encrypted key resolver. + * + * @return the encrypted key resolver + */ + public EncryptedKeyResolver getEncryptedKeyResolver() { + return encKeyResolver; + } + + /** + * Set a new encrypted key resolver. + * + * @param newResolver the new encrypted key resolver + */ + public void setEncryptedKeyResolver(EncryptedKeyResolver newResolver) { + encKeyResolver = newResolver; + } + + /** + * Get the optional static set of criteria used when resolving credentials based on the KeyInfo of an EncryptedData + * element. + * + * @return the static criteria set to use + */ + public CriteriaSet setKeyResolverCriteria() { + return resolverCriteria; + } + + /** + * Set the optional static set of criteria used when resolving credentials based on the KeyInfo of an EncryptedData + * element. + * + * @param newCriteria the static criteria set to use + */ + public void setKeyResolverCriteria(CriteriaSet newCriteria) { + resolverCriteria = newCriteria; + } + + /** + * Get the optional static set of criteria used when resolving credentials based on the KeyInfo of an EncryptedKey + * element. + * + * @return the static criteria set to use + */ + public CriteriaSet getKEKResolverCriteria() { + return kekResolverCriteria; + } + + /** + * Set the optional static set of criteria used when resolving credentials based on the KeyInfo of an EncryptedKey + * element. + * + * @param newCriteria the static criteria set to use + */ + public void setKEKResolverCriteria(CriteriaSet newCriteria) { + kekResolverCriteria = newCriteria; + } + + /** + * This is a convenience method for calling {@link #decryptData(EncryptedData, boolean)}, + * with the rootInNewDocument parameter value supplied by {@link #isRootInNewDocument()}. + * + * @param encryptedData encrypted data element containing the data to be decrypted + * @return the decrypted XMLObject + * @throws DecryptionException exception indicating a decryption error, possibly because the decrypted data + * contained more than one top-level Element, or some non-Element Node type. + */ + public XMLObject decryptData(EncryptedData encryptedData) throws DecryptionException { + return decryptData(encryptedData, isRootInNewDocument()); + } + + /** + * Decrypts the supplied EncryptedData and returns the resulting XMLObject. + * + * This will only succeed if the decrypted EncryptedData contains exactly one DOM Node of type Element. + * + * @param encryptedData encrypted data element containing the data to be decrypted + * @param rootInNewDocument if true, root the underlying Element of the returned XMLObject in a new Document as + * described in {@link Decrypter} + * @return the decrypted XMLObject + * @throws DecryptionException exception indicating a decryption error, possibly because the decrypted data + * contained more than one top-level Element, or some non-Element Node type. + */ + public XMLObject decryptData(EncryptedData encryptedData, boolean rootInNewDocument) throws DecryptionException { + + List xmlObjects = decryptDataToList(encryptedData, rootInNewDocument); + if (xmlObjects.size() != 1) { + log.error("The decrypted data contained more than one top-level XMLObject child"); + throw new DecryptionException("The decrypted data contained more than one XMLObject child"); + } + + return xmlObjects.get(0); + } + + /** + * This is a convenience method for calling {@link #decryptDataToList(EncryptedData, boolean)}, + * with the rootInNewDocument parameter value supplied by {@link #isRootInNewDocument()}. + * + * @param encryptedData encrypted data element containing the data to be decrypted + * @return the list decrypted top-level XMLObjects + * @throws DecryptionException exception indicating a decryption error, possibly because the decrypted data + * contained DOM nodes other than type of Element + */ + public List decryptDataToList(EncryptedData encryptedData) throws DecryptionException { + return decryptDataToList(encryptedData, isRootInNewDocument()); + } + + /** + * Decrypts the supplied EncryptedData and returns the resulting list of XMLObjects. + * + * This will succeed only if the decrypted EncryptedData contains at the top-level only DOM Elements (not other + * types of DOM Nodes). + * + * @param encryptedData encrypted data element containing the data to be decrypted + * @param rootInNewDocument if true, root the underlying Elements of the returned XMLObjects in a new Document as + * described in {@link Decrypter} + * @return the list decrypted top-level XMLObjects + * @throws DecryptionException exception indicating a decryption error, possibly because the decrypted data + * contained DOM nodes other than type of Element + */ + public List decryptDataToList(EncryptedData encryptedData, boolean rootInNewDocument) + throws DecryptionException { + List xmlObjects = new LinkedList(); + + DocumentFragment docFragment = decryptDataToDOM(encryptedData); + + XMLObject xmlObject; + Node node; + Element element; + + NodeList children = docFragment.getChildNodes(); + for (int i = 0; i < children.getLength(); i++) { + node = children.item(i); + if (node.getNodeType() != Node.ELEMENT_NODE) { + log.error("Decryption returned a top-level node that was not of type Element: " + node.getNodeType()); + throw new DecryptionException("Top-level node was not of type Element"); + } else { + element = (Element) node; + if (rootInNewDocument) { + Document newDoc = null; + try { + newDoc = parserPool.newDocument(); + } catch (XMLParserException e) { + log.error("There was an error creating a new DOM Document", e); + throw new DecryptionException("Error creating new DOM Document", e); + } + newDoc.adoptNode(element); + newDoc.appendChild(element); + } + } + + try { + xmlObject = unmarshallerFactory.getUnmarshaller(element).unmarshall(element); + } catch (UnmarshallingException e) { + log.error("There was an error during unmarshalling of the decrypted element", e); + throw new DecryptionException("Unmarshalling error during decryption", e); + } + + xmlObjects.add(xmlObject); + } + + return xmlObjects; + } + + /** + * Decrypts the supplied EncryptedData and returns the resulting DOM {@link DocumentFragment}. + * + * @param encryptedData encrypted data element containing the data to be decrypted + * @return the decrypted DOM {@link DocumentFragment} + * @throws DecryptionException exception indicating a decryption error + */ + public DocumentFragment decryptDataToDOM(EncryptedData encryptedData) throws DecryptionException { + if (resolver == null && encKeyResolver == null) { + log.error("Decryption can not be attempted, required resolvers are not available"); + throw new DecryptionException("Unable to decrypt EncryptedData, required resolvers are not available"); + } + + DocumentFragment docFrag = null; + + if (resolver != null) { + docFrag = decryptUsingResolvedKey(encryptedData); + if (docFrag != null) { + return docFrag; + } else { + log.debug("Failed to decrypt EncryptedData using standard KeyInfo resolver"); + } + } + + String algorithm = encryptedData.getEncryptionMethod().getAlgorithm(); + if (DatatypeHelper.isEmpty(algorithm)) { + String msg = "EncryptedData's EncryptionMethod Algorithm attribute was empty, " + + "key decryption could not be attempted"; + log.error(msg); + throw new DecryptionException(msg); + } + + if (encKeyResolver != null) { + docFrag = decryptUsingResolvedEncryptedKey(encryptedData, algorithm); + if (docFrag != null) { + return docFrag; + } else { + log.debug("Failed to decrypt EncryptedData using EncryptedKeyResolver"); + } + } + + log.error("Failed to decrypt EncryptedData using either EncryptedData KeyInfoCredentialResolver " + + "or EncryptedKeyResolver + EncryptedKey KeyInfoCredentialResolver"); + + throw new DecryptionException("Failed to decrypt EncryptedData"); + } + + /** + * Decrypts the supplied EncryptedData using the specified key, and returns the resulting DOM + * {@link DocumentFragment}. + * + * @param encryptedData encrypted data element containing the data to be decrypted + * @param dataEncKey Java Key with which to attempt decryption of the encrypted data + * @return the decrypted DOM {@link DocumentFragment} + * @throws DecryptionException exception indicating a decryption error + */ + public DocumentFragment decryptDataToDOM(EncryptedData encryptedData, Key dataEncKey) throws DecryptionException { + + // TODO Until Xerces supports LSParser.parseWithContext(), or we come up with another solution + // to parse a bytestream into a DocumentFragment, we can only support encryption of type + // Element (i.e. a single Element), not content. + if (!EncryptionConstants.TYPE_ELEMENT.equals(encryptedData.getType())) { + log.error("EncryptedData was of unsupported type '" + encryptedData.getType() + + "', could not attempt decryption"); + throw new DecryptionException("EncryptedData of unsupported type was encountered"); + } + if (dataEncKey == null) { + log.error("Data decryption key was null"); + throw new IllegalArgumentException("Data decryption key may not be null"); + } + + try { + checkAndMarshall(encryptedData); + } catch (DecryptionException e) { + log.error("Error marshalling EncryptedData for decryption", e); + throw e; + } + Element targetElement = encryptedData.getDOM(); + + XMLCipher xmlCipher; + try { + if (getJCAProviderName() != null) { + xmlCipher = XMLCipher.getProviderInstance(getJCAProviderName()); + } else { + xmlCipher = XMLCipher.getInstance(); + } + xmlCipher.init(XMLCipher.DECRYPT_MODE, dataEncKey); + } catch (XMLEncryptionException e) { + log.error("Error initialzing cipher instance on data decryption", e); + throw new DecryptionException("Error initialzing cipher instance on data decryption", e); + } + + byte[] bytes = null; + try { + bytes = xmlCipher.decryptToByteArray(targetElement); + } catch (XMLEncryptionException e) { + log.error("Error decrypting the encrypted data element", e); + throw new DecryptionException("Error decrypting the encrypted data element", e); + } + if (bytes == null) { + throw new DecryptionException("EncryptedData could not be decrypted"); + } + ByteArrayInputStream input = new ByteArrayInputStream(bytes); + DocumentFragment docFragment = parseInputStream(input, encryptedData.getDOM().getOwnerDocument()); + return docFragment; + } + + /** + * Attempts to decrypt the supplied EncryptedKey and returns the resulting Java security Key object. The algorithm + * of the decrypted key must be supplied by the caller based on knowledge of the associated EncryptedData + * information. + * + * @param encryptedKey encrypted key element containing the encrypted key to be decrypted + * @param algorithm the algorithm associated with the decrypted key + * @return the decrypted key + * @throws DecryptionException exception indicating a decryption error + */ + public Key decryptKey(EncryptedKey encryptedKey, String algorithm) throws DecryptionException { + if (kekResolver == null) { + log.warn("No KEK KeyInfo credential resolver is available, can not attempt EncryptedKey decryption"); + throw new DecryptionException("No KEK KeyInfo resolver is available for EncryptedKey decryption"); + } + + if (DatatypeHelper.isEmpty(algorithm)) { + log.error("Algorithm of encrypted key not supplied, key decryption cannot proceed."); + throw new DecryptionException("Algorithm of encrypted key not supplied, key decryption cannot proceed."); + } + + CriteriaSet criteriaSet = buildCredentialCriteria(encryptedKey, kekResolverCriteria); + try { + for (Credential cred : kekResolver.resolve(criteriaSet)) { + try { + return decryptKey(encryptedKey, algorithm, SecurityHelper.extractDecryptionKey(cred)); + } catch (DecryptionException e) { + String msg = "Attempt to decrypt EncryptedKey using credential from KEK KeyInfo resolver failed: "; + log.debug(msg, e); + continue; + } + } + } catch (SecurityException e) { + log.error("Error resolving credentials from EncryptedKey KeyInfo", e); + } + + log.error("Failed to decrypt EncryptedKey, valid decryption key could not be resolved"); + throw new DecryptionException("Valid decryption key for EncryptedKey could not be resolved"); + } + + /** + * Decrypts the supplied EncryptedKey and returns the resulting Java security Key object. The algorithm of the + * decrypted key must be supplied by the caller based on knowledge of the associated EncryptedData information. + * + * @param encryptedKey encrypted key element containing the encrypted key to be decrypted + * @param algorithm the algorithm associated with the decrypted key + * @param kek the key encryption key with which to attempt decryption of the encrypted key + * @return the decrypted key + * @throws DecryptionException exception indicating a decryption error + */ + public Key decryptKey(EncryptedKey encryptedKey, String algorithm, Key kek) throws DecryptionException { + if (kek == null) { + log.error("Data encryption key was null"); + throw new IllegalArgumentException("Data encryption key may not be null"); + } + if (DatatypeHelper.isEmpty(algorithm)) { + log.error("Algorithm of encrypted key not supplied, key decryption cannot proceed."); + throw new DecryptionException("Algorithm of encrypted key not supplied, key decryption cannot proceed."); + } + + try { + checkAndMarshall(encryptedKey); + } catch (DecryptionException e) { + log.error("Error marshalling EncryptedKey for decryption", e); + throw e; + } + + preProcessEncryptedKey(encryptedKey, algorithm, kek); + + Element targetElement = encryptedKey.getDOM(); + + XMLCipher xmlCipher; + try { + if (getJCAProviderName() != null) { + xmlCipher = XMLCipher.getProviderInstance(getJCAProviderName()); + } else { + xmlCipher = XMLCipher.getInstance(); + } + xmlCipher.init(XMLCipher.UNWRAP_MODE, kek); + } catch (XMLEncryptionException e) { + log.error("Error initialzing cipher instance on key decryption", e); + throw new DecryptionException("Error initialzing cipher instance on key decryption", e); + } + + org.apache.xml.security.encryption.EncryptedKey encKey; + try { + encKey = xmlCipher.loadEncryptedKey(targetElement.getOwnerDocument(), targetElement); + } catch (XMLEncryptionException e) { + log.error("Error when loading library native encrypted key representation", e); + throw new DecryptionException("Error when loading library native encrypted key representation", e); + } + + Key key = null; + try { + key = xmlCipher.decryptKey(encKey, algorithm); + } catch (XMLEncryptionException e) { + log.error("Error decrypting encrypted key", e); + throw new DecryptionException("Error decrypting encrypted key", e); + } + if (key == null) { + throw new DecryptionException("Key could not be decrypted"); + } + return key; + } + + /** + * Preprocess the EncryptedKey. For example, check for supported algorithms. + * + * @param encryptedKey encrypted key element containing the encrypted key to be decrypted + * @param algorithm the algorithm associated with the decrypted key + * @param kek the key encryption key with which to attempt decryption of the encrypted key + * + * @throws DecryptionException exception indicating a decryption error + */ + protected void preProcessEncryptedKey(EncryptedKey encryptedKey, String algorithm, Key kek) + throws DecryptionException { + + // Apache XML-Security currently only supports an internal, hard-coded default + // SHA-1 digest method with RSA-OAEP key transport. + String keyTransportAlgorithm = encryptedKey.getEncryptionMethod().getAlgorithm(); + if (EncryptionConstants.ALGO_ID_KEYTRANSPORT_RSAOAEP.equals(keyTransportAlgorithm)) { + List digestMethods = + encryptedKey.getEncryptionMethod().getUnknownXMLObjects(DigestMethod.DEFAULT_ELEMENT_NAME); + if (!digestMethods.isEmpty()) { + DigestMethod dm = (DigestMethod) digestMethods.get(0); + if (! SignatureConstants.ALGO_ID_DIGEST_SHA1 + .equals(DatatypeHelper.safeTrimOrNullString(dm.getAlgorithm())) ) { + log.error("EncryptedKey/EncryptionMethod/DigestMethod contains unsupported algorithm URI: {}", + dm.getAlgorithm()); + throw new DecryptionException( + "EncryptedKey/EncryptionMethod/DigestMethod contains unsupported algorithm URI"); + } + } + } + + } + + /** + * Attempt to decrypt by resolving the decryption key using the standard credential resolver. + * + * @param encryptedData the encrypted data to decrypt + * @return the decrypted document fragment, or null if decryption key could not be resolved or decryption failed + */ + private DocumentFragment decryptUsingResolvedKey(EncryptedData encryptedData) { + if (resolver != null) { + CriteriaSet criteriaSet = buildCredentialCriteria(encryptedData, resolverCriteria); + try { + for (Credential cred : resolver.resolve(criteriaSet)) { + try { + return decryptDataToDOM(encryptedData, SecurityHelper.extractDecryptionKey(cred)); + } catch (DecryptionException e) { + String msg = "Decryption attempt using credential from standard KeyInfo resolver failed: "; + log.debug(msg, e); + continue; + } + } + } catch (SecurityException e) { + log.error("Error resolving credentials from EncryptedData KeyInfo", e); + } + } + return null; + } + + /** + * Attempt to decrypt by resolving the decryption key by first resolving EncryptedKeys, and using the KEK credential + * resolver to resolve the key decryption for each. + * + * @param encryptedData the encrypted data to decrypt + * @param algorithm the algorithm of the key to be decrypted + * @return the decrypted document fragment, or null if decryption key could not be resolved or decryption failed + */ + private DocumentFragment decryptUsingResolvedEncryptedKey(EncryptedData encryptedData, String algorithm) { + if (encKeyResolver != null) { + for (EncryptedKey encryptedKey : encKeyResolver.resolve(encryptedData)) { + try { + Key decryptedKey = decryptKey(encryptedKey, algorithm); + return decryptDataToDOM(encryptedData, decryptedKey); + } catch (DecryptionException e) { + String msg = "Attempt to decrypt EncryptedData using key extracted from EncryptedKey failed: "; + log.debug(msg, e); + continue; + } + } + } + return null; + } + + /** + * Parse the specified input stream in a DOM DocumentFragment, owned by the specified Document. + * + * @param input the InputStream to parse + * @param owningDocument the Document which will own the returned DocumentFragment + * @return a DocumentFragment + * @throws DecryptionException thrown if there is an error parsing the input stream + */ + private DocumentFragment parseInputStream(InputStream input, Document owningDocument) throws DecryptionException { + // Since Xerces currently seems not to handle parsing into a DocumentFragment + // without a bit hackery, use this to simulate, so we can keep the API + // the way it hopefully will look in the future. Obviously this only works for + // input streams containing valid XML instances, not fragments. + + Document newDocument = null; + try { + newDocument = parserPool.parse(input); + } catch (XMLParserException e) { + log.error("Error parsing decrypted input stream", e); + throw new DecryptionException("Error parsing input stream", e); + } + + Element element = newDocument.getDocumentElement(); + owningDocument.adoptNode(element); + + DocumentFragment container = owningDocument.createDocumentFragment(); + container.appendChild(element); + + return container; + } + + /** + * Utility method to build a new set of credential criteria based on the KeyInfo of an EncryptedData or + * EncryptedKey, and any additional static criteria which might have been supplied to the decrypter. + * + * @param encryptedType an EncryptedData or EncryptedKey for which to resolve decryption credentials + * @param staticCriteria static set of credential criteria to add to the new criteria set + * @return the new credential criteria set + */ + private CriteriaSet buildCredentialCriteria(EncryptedType encryptedType, CriteriaSet staticCriteria) { + + CriteriaSet newCriteriaSet = new CriteriaSet(); + + // This is the main criteria based on the encrypted type's KeyInfo + newCriteriaSet.add(new KeyInfoCriteria(encryptedType.getKeyInfo())); + + // Also attemtpt to dynamically construct key criteria based on information + // in the encrypted object + Set keyCriteria = buildKeyCriteria(encryptedType); + if (keyCriteria != null && !keyCriteria.isEmpty()) { + newCriteriaSet.addAll(keyCriteria); + } + + // Add any static criteria which may have been supplied to the decrypter + if (staticCriteria != null && !staticCriteria.isEmpty()) { + newCriteriaSet.addAll(staticCriteria); + } + + // If don't have a usage criteria yet from static criteria, add encryption usage + if (!newCriteriaSet.contains(UsageCriteria.class)) { + newCriteriaSet.add(new UsageCriteria(UsageType.ENCRYPTION)); + } + + return newCriteriaSet; + } + + /** + * Build decryption key credential criteria according to information in the encrypted type object. + * + * @param encryptedType the encrypted type from which to deduce decryption key criteria + * @return a set of credential criteria pertaining to the decryption key + */ + private Set buildKeyCriteria(EncryptedType encryptedType) { + EncryptionMethod encMethod = encryptedType.getEncryptionMethod(); + if (encMethod == null) { + // This element is optional + return Collections.emptySet(); + } + String encAlgorithmURI = DatatypeHelper.safeTrimOrNullString(encMethod.getAlgorithm()); + if (encAlgorithmURI == null) { + return Collections.emptySet(); + } + + Set critSet = new HashSet(2); + + KeyAlgorithmCriteria algoCrit = buildKeyAlgorithmCriteria(encAlgorithmURI); + if (algoCrit != null) { + critSet.add(algoCrit); + log.debug("Added decryption key algorithm criteria: {}", algoCrit.getKeyAlgorithm()); + } + + KeyLengthCriteria lengthCrit = buildKeyLengthCriteria(encAlgorithmURI); + if (lengthCrit != null) { + critSet.add(lengthCrit); + log.debug("Added decryption key length criteria from EncryptionMethod algorithm URI: {}", lengthCrit + .getKeyLength()); + } else { + if (encMethod.getKeySize() != null && encMethod.getKeySize().getValue() != null) { + lengthCrit = new KeyLengthCriteria(encMethod.getKeySize().getValue()); + critSet.add(lengthCrit); + log.debug("Added decryption key length criteria from EncryptionMethod/KeySize: {}", lengthCrit + .getKeyLength()); + } + } + + return critSet; + } + + /** + * Dynamically construct key algorithm credential criteria based on the specified algorithm URI. + * + * @param encAlgorithmURI the algorithm URI + * @return a new key algorithm credential criteria instance, or null if criteria could not be determined + */ + private KeyAlgorithmCriteria buildKeyAlgorithmCriteria(String encAlgorithmURI) { + if (DatatypeHelper.isEmpty(encAlgorithmURI)) { + return null; + } + + String jcaKeyAlgorithm = SecurityHelper.getKeyAlgorithmFromURI(encAlgorithmURI); + if (!DatatypeHelper.isEmpty(jcaKeyAlgorithm)) { + return new KeyAlgorithmCriteria(jcaKeyAlgorithm); + } + + return null; + } + + /** + * Dynamically construct key length credential criteria based on the specified algorithm URI. + * + * @param encAlgorithmURI the algorithm URI + * @return a new key length credential criteria instance, or null if the value could not be determined + */ + private KeyLengthCriteria buildKeyLengthCriteria(String encAlgorithmURI) { + if (!DatatypeHelper.isEmpty(encAlgorithmURI)) { + return null; + } + + Integer keyLength = SecurityHelper.getKeyLengthFromURI(encAlgorithmURI); + if (keyLength != null) { + return new KeyLengthCriteria(keyLength); + } + + return null; + } + + /** + * Ensure that the XMLObject is marshalled. + * + * @param xmlObject the object to check and marshall + * @throws DecryptionException thrown if there is an error when marshalling the XMLObject + */ + protected void checkAndMarshall(XMLObject xmlObject) throws DecryptionException { + Element targetElement = xmlObject.getDOM(); + if (targetElement == null) { + Marshaller marshaller = Configuration.getMarshallerFactory().getMarshaller(xmlObject); + try { + targetElement = marshaller.marshall(xmlObject); + } catch (MarshallingException e) { + log.error("Error marshalling target XMLObject", e); + throw new DecryptionException("Error marshalling target XMLObject", e); + } + } + } + + /* + * NOTE: this currently won't work because Xerces doesn't implement LSParser.parseWithContext(). Hopefully they will + * in the future. + */ + /* + * private DocumentFragment parseInputStreamLS(InputStream input, Document owningDocument) throws + * DecryptionException { + * + * DOMImplementationLS domImpl = getDOMImplemenationLS(); + * + * LSParser parser = domImpl.createLSParser(DOMImplementationLS.MODE_SYNCHRONOUS, null); if (parser == null) { throw + * new DecryptionException("LSParser was null"); } + * + * //DOMConfiguration config=parser.getDomConfig(); //DOMErrorHandlerImpl errorHandler=new DOMErrorHandlerImpl(); + * //config.setParameter("error-handler", errorHandler); + * + * LSInput lsInput = domImpl.createLSInput(); if (lsInput == null) { throw new DecryptionException("LSInput was + * null"); } lsInput.setByteStream(input); + * + * DocumentFragment container = owningDocument.createDocumentFragment(); //TODO Xerces currently doesn't support + * LSParser.parseWithContext() parser.parseWithContext(lsInput, container, LSParser.ACTION_REPLACE_CHILDREN); + * + * return container; } + */ + + /* + * private DOMImplementationLS getDOMImplemenationLS() throws DecryptionException { if (domImplLS != null) { return + * domImplLS; } + * // get an instance of the DOMImplementation registry DOMImplementationRegistry registry; try { registry = + * DOMImplementationRegistry.newInstance(); } catch (ClassCastException e) { throw new DecryptionException("Error + * creating new error of DOMImplementationRegistry", e); } catch (ClassNotFoundException e) { throw new + * DecryptionException("Error creating new error of DOMImplementationRegistry", e); } catch (InstantiationException + * e) { throw new DecryptionException("Error creating new error of DOMImplementationRegistry", e); } catch + * (IllegalAccessException e) { throw new DecryptionException("Error creating new error of + * DOMImplementationRegistry", e); } + * // get a new instance of the DOM Level 3 Load/Save implementation DOMImplementationLS newDOMImplLS = + * (DOMImplementationLS) registry.getDOMImplementation("LS 3.0"); if (newDOMImplLS == null) { throw new + * DecryptionException("No LS DOMImplementation could be found"); } else { domImplLS = newDOMImplLS; } + * + * return domImplLS; } + */ + + /* + * Initialize the Apache XML security library if it hasn't been already + */ + static { + if (!Init.isInitialized()) { + Init.init(); + } + } + +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/DecryptionException.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/DecryptionException.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/DecryptionException.java 17 Aug 2012 15:16:59 -0000 1.1 @@ -0,0 +1,66 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption; + +/** + * Exception thrown when an error occurs during decryption operations. + */ +public class DecryptionException extends Exception { + + /** + * Serial version UID. + */ + private static final long serialVersionUID = 7785660781162212790L; + + /** + * Constructor. + */ + public DecryptionException() { + super(); + } + + /** + * Constructor. + * + * @param message exception message + */ + public DecryptionException(String message) { + super(message); + } + + /** + * Constructor. + * + * @param wrappedException exception to be wrapped by this one + */ + public DecryptionException(Exception wrappedException) { + super(wrappedException); + } + + /** + * Constructor. + * + * @param message exception message + * @param wrappedException exception to be wrapped by this one + */ + public DecryptionException(String message, Exception wrappedException) { + super(message, wrappedException); + } + + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/EncryptedData.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/EncryptedData.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/EncryptedData.java 17 Aug 2012 15:16:58 -0000 1.1 @@ -0,0 +1,43 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption; + +import javax.xml.namespace.QName; + +import org.opensaml.xml.util.XMLConstants; + +/** + * XMLObject representing XML Encryption, version 20021210, EncryptedData element. + */ +public interface EncryptedData extends EncryptedType { + + /** Element local name. */ + public static final String DEFAULT_ELEMENT_LOCAL_NAME = "EncryptedData"; + + /** Default element name. */ + public static final QName DEFAULT_ELEMENT_NAME = new QName(XMLConstants.XMLENC_NS, DEFAULT_ELEMENT_LOCAL_NAME, + XMLConstants.XMLENC_PREFIX); + + /** Local name of the XSI type. */ + public static final String TYPE_LOCAL_NAME = "EncryptedDataType"; + + /** QName of the XSI type. */ + public static final QName TYPE_NAME = new QName(XMLConstants.XMLENC_NS, TYPE_LOCAL_NAME, + XMLConstants.XMLENC_PREFIX); + +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/EncryptedKey.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/EncryptedKey.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/EncryptedKey.java 17 Aug 2012 15:16:59 -0000 1.1 @@ -0,0 +1,90 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption; + +import javax.xml.namespace.QName; + +import org.opensaml.xml.util.XMLConstants; + +/** + * XMLObject representing XML Encryption, version 20021210, EncryptedKey element. + */ +public interface EncryptedKey extends EncryptedType { + + /** Element local name. */ + public static final String DEFAULT_ELEMENT_LOCAL_NAME = "EncryptedKey"; + + /** Default element name. */ + public static final QName DEFAULT_ELEMENT_NAME = new QName(XMLConstants.XMLENC_NS, DEFAULT_ELEMENT_LOCAL_NAME, + XMLConstants.XMLENC_PREFIX); + + /** Local name of the XSI type. */ + public static final String TYPE_LOCAL_NAME = "EncryptedKeyType"; + + /** QName of the XSI type. */ + public static final QName TYPE_NAME = new QName(XMLConstants.XMLENC_NS, TYPE_LOCAL_NAME, + XMLConstants.XMLENC_PREFIX); + + /** Recipient attribute name. */ + public static final String RECIPIENT_ATTRIB_NAME = "Recipient"; + + /** + * Gets the hint about for whom this encrypted key is intended. + * + * @return the hint about who this encrypted key is intended for + */ + public String getRecipient(); + + /** + * Sets the hint about for whom this encrypted key is intended. + * + * @param newRecipient the hint about who this encrypted key is intended for + */ + public void setRecipient(String newRecipient); + + /** + * Gets the child element containing pointers to EncryptedData and EncryptedKey elements + * encrypted using this key. + * + * @return the element containing a list of pointers to encrypted elements + */ + public ReferenceList getReferenceList(); + + /** + * Sets the child element containing pointers to EncryptedData and EncryptedKey elements + * encrypted using this key. + * + * @param newReferenceList the new reference list for this encrypted key + */ + public void setReferenceList(ReferenceList newReferenceList); + + /** + * Gets the child element carrying the human readable name for this key. + * + * @return the human readable name for this key + */ + public CarriedKeyName getCarriedKeyName(); + + /** + * Sets the child element carrying the human readable name for this key. + * + * @param newCarriedKeyName the human readable name for this key + */ + public void setCarriedKeyName(CarriedKeyName newCarriedKeyName); + +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/EncryptedKeyResolver.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/EncryptedKeyResolver.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/EncryptedKeyResolver.java 17 Aug 2012 15:16:57 -0000 1.1 @@ -0,0 +1,48 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption; + +import java.util.List; + +/** + * Interface for resolving {@link EncryptedKey} elements based on a particular + * {@link EncryptedData} context, primarily for use during the decryption process. + * + * The resolved EncryptedKey element(s) will contain the data encryption key used to encrypt + * the specified EncryptedData. + */ +public interface EncryptedKeyResolver { + + /** + * Resolve the EncryptedKey elements containing the data encryption key used to + * encrypt the specified EncryptedData element. + * + * @param encryptedData the EncryptedData element context in which to resolve + * @return an iterable of EncryptedKey elements + */ + Iterable resolve(EncryptedData encryptedData); + + /** + * Get the list of recipient criteria used by this resolver, and against which a candidate + * EncryptedKey's Recipient attribute is evaluated. + * + * @return the list of recipient criteria + */ + List getRecipients(); + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/EncryptedType.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/EncryptedType.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/EncryptedType.java 17 Aug 2012 15:16:58 -0000 1.1 @@ -0,0 +1,163 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption; + +import javax.xml.namespace.QName; + +import org.opensaml.xml.signature.KeyInfo; +import org.opensaml.xml.util.XMLConstants; +import org.opensaml.xml.validation.ValidatingXMLObject; + +/** + * XMLObject representing XML Encryption, version 20021210, EncryptedType type. This is the base type for + * {@link EncryptedData} and {@link EncryptedKey} types. + */ +public interface EncryptedType extends ValidatingXMLObject { + + /** Local name of the XSI type. */ + public static final String TYPE_LOCAL_NAME = "EncryptedType"; + + /** QName of the XSI type. */ + public static final QName TYPE_NAME = new QName(XMLConstants.XMLENC_NS, TYPE_LOCAL_NAME, + XMLConstants.XMLENC_PREFIX); + + /** Id attribute name. */ + public static final String ID_ATTRIB_NAME = "Id"; + + /** Type attribute name. */ + public static final String TYPE_ATTRIB_NAME = "Type"; + + /** MimeType attribute name. */ + public static final String MIMETYPE_ATTRIB_NAME = "MimeType"; + + /** Encoding attribute name. */ + public static final String ENCODING_ATTRIB_NAME = "Encoding"; + + /** + * Gets the unique ID for the XML element. + * + * @return the unique ID for the XML element + */ + public String getID(); + + /** + * Sets the unique ID for the XML element. + * + * @param newID the unique ID for the XML element + */ + public void setID(String newID); + + /** + * Gets the type information for the plaintext content. + * + * @return the type information for the plaintext content + */ + public String getType(); + + /** + * Sets the type information for the plaintext content. + * + * @param newType the type information for the plaintext content + */ + public void setType(String newType); + + /** + * Gets the MIME type of the plaintext content. + * + * @return the MIME type of the plaintext content + */ + public String getMimeType(); + + /** + * Sets the MIME type of the plaintext content. + * + * @param newMimeType the MIME type of the plaintext content + */ + public void setMimeType(String newMimeType); + + /** + * Gets the encoding applied to the plaintext content prior to encryption. + * + * @return the encoding applied to the plaintext content prior to encryption + */ + public String getEncoding(); + + /** + * Sets the encoding applied to the plaintext content prior to encryption. + * + * @param newEncoding the encoding applied to the plaintext content prior to encryption + */ + public void setEncoding(String newEncoding); + + /** + * Gets the EncryptionMethod child element. + * + * @return the EncryptionMethod child element + */ + public EncryptionMethod getEncryptionMethod(); + + /** + * Sets the EncryptionMethod child element. + * + * @param newEncryptionMethod the new EncryptionMethod child element + */ + public void setEncryptionMethod(EncryptionMethod newEncryptionMethod); + + /** + * Gets the KeyInfo child element. + * + * @return the KeyInfo child element + */ + public KeyInfo getKeyInfo(); + + /** + * Sets the KeyInfo child element. + * + * @param newKeyInfo the new KeyInfo child element + */ + public void setKeyInfo(KeyInfo newKeyInfo); + + /** + * Gets the CipherData child element. + * + * @return the CipherData child element + */ + public CipherData getCipherData(); + + /** + * Sets the CipherData child element. + * + * @param newCipherData the new CipherData child element + */ + public void setCipherData(CipherData newCipherData); + + /** + * Gets the EncryptionProperties child element. + * + * @return the EncryptionProperties child element + */ + public EncryptionProperties getEncryptionProperties(); + + /** + * Sets the EncryptionProperties child element. + * + * @param newEncryptionProperties the new EncryptionProperties child element + */ + public void setEncryptionProperties(EncryptionProperties newEncryptionProperties); + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/Encrypter.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/Encrypter.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/Encrypter.java 17 Aug 2012 15:16:58 -0000 1.1 @@ -0,0 +1,666 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption; + +import java.security.Key; +import java.security.KeyException; +import java.security.NoSuchAlgorithmException; +import java.security.interfaces.DSAPublicKey; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import javax.crypto.SecretKey; + +import org.apache.xml.security.Init; +import org.apache.xml.security.encryption.XMLCipher; +import org.apache.xml.security.encryption.XMLEncryptionException; +import org.opensaml.xml.Configuration; +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.XMLObjectBuilderFactory; +import org.opensaml.xml.io.Marshaller; +import org.opensaml.xml.io.MarshallingException; +import org.opensaml.xml.io.Unmarshaller; +import org.opensaml.xml.io.UnmarshallerFactory; +import org.opensaml.xml.io.UnmarshallingException; +import org.opensaml.xml.security.SecurityException; +import org.opensaml.xml.security.SecurityHelper; +import org.opensaml.xml.security.keyinfo.KeyInfoGenerator; +import org.opensaml.xml.signature.DigestMethod; +import org.opensaml.xml.signature.KeyInfo; +import org.opensaml.xml.signature.SignatureConstants; +import org.opensaml.xml.signature.XMLSignatureBuilder; +import org.opensaml.xml.util.DatatypeHelper; +import org.opensaml.xml.util.XMLConstants; +import org.opensaml.xml.util.XMLHelper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +/** + * Supports encryption of XMLObjects, their content and keys, according to the XML Encryption specification, version + * 20021210. + * + *

+ * Various overloaded method variants are supplied for encrypting XMLObjects and their contents (with or without + * encryption of the associated data encryption key), as well as for encrypting keys separately. + *

+ * + *

+ * The parameters for data encryption are specified with an instance of {@link EncryptionParameters}. The parameters + * for key encryption are specified with one or more instances of {@link KeyEncryptionParameters}. + *

+ * + *

+ * The data encryption credential supplied by {@link EncryptionParameters#getEncryptionCredential()} is mandatory unless + * key encryption is also being performed and all associated key encryption parameters contain a valid key encryption + * credential containing a valid key encryption key. In this case the data encryption key will be randomly generated + * based on the algorithm URI supplied by {@link EncryptionParameters#getAlgorithm()}. + *

+ * + *

+ * If encryption of the data encryption key is being performed using the overloaded methods for elements or content, the + * resulting EncryptedKey(s) will be placed inline within the KeyInfo of the resulting EncryptedData. If this is not the + * desired behavior, the XMLObject and the data encryption key should be encrypted separately, and the placement of + * EncryptedKey(s) handled by the caller. Specialized subclasses of this class maybe also handle key placement in an + * application-specific manner. + *

+ * + */ +public class Encrypter { + + /** Class logger. */ + private final Logger log = LoggerFactory.getLogger(Encrypter.class); + + /** Unmarshaller used to create EncryptedData objects from DOM element. */ + private Unmarshaller encryptedDataUnmarshaller; + + /** Unmarshaller used to create EncryptedData objects from DOM element. */ + private Unmarshaller encryptedKeyUnmarshaller; + + /** Builder instance for building KeyInfo objects. */ + private XMLSignatureBuilder keyInfoBuilder; + + /** The name of the JCA security provider to use. */ + private String jcaProviderName; + + /** + * Constructor. + * + */ + public Encrypter() { + UnmarshallerFactory unmarshallerFactory = Configuration.getUnmarshallerFactory(); + encryptedDataUnmarshaller = unmarshallerFactory.getUnmarshaller(EncryptedData.DEFAULT_ELEMENT_NAME); + encryptedKeyUnmarshaller = unmarshallerFactory.getUnmarshaller(EncryptedKey.DEFAULT_ELEMENT_NAME); + + XMLObjectBuilderFactory builderFactory = Configuration.getBuilderFactory(); + keyInfoBuilder = (XMLSignatureBuilder) builderFactory.getBuilder(KeyInfo.DEFAULT_ELEMENT_NAME); + + jcaProviderName = null; + } + + /** + * Get the Java Cryptography Architecture (JCA) security provider name that should be used to provide the encryption + * support. + * + * Defaults to null, which means that the first registered provider which supports the requested + * encryption algorithm URI will be used. + * + * @return the JCA provider name to use + */ + public String getJCAProviderName() { + return jcaProviderName; + } + + /** + * Set the Java Cryptography Architecture (JCA) security provider name that should be used to provide the encryption + * support. + * + * Defaults to null, which means that the first registered provider which supports the requested + * encryption algorithm URI will be used. + * + * @param providerName the JCA provider name to use + */ + public void setJCAProviderName(String providerName) { + jcaProviderName = providerName; + } + + /** + * Encrypts the DOM representation of the XMLObject. + * + * @param xmlObject the XMLObject to be encrypted + * @param encParams parameters for encrypting the data + * + * @return the resulting EncryptedData element + * @throws EncryptionException exception thrown on encryption errors + */ + public EncryptedData encryptElement(XMLObject xmlObject, EncryptionParameters encParams) + throws EncryptionException { + List emptyKEKParamsList = new ArrayList(); + return encryptElement(xmlObject, encParams, emptyKEKParamsList, false); + } + + /** + * Encrypts the DOM representation of the XMLObject, encrypts the encryption key using the specified key encryption + * parameters and places the resulting EncryptedKey within the EncryptedData's KeyInfo. + * + * @param xmlObject the XMLObject to be encrypted + * @param encParams parameters for encrypting the data + * @param kekParams parameters for encrypting the encryption key + * + * @return the resulting EncryptedData element + * @throws EncryptionException exception thrown on encryption errors + */ + public EncryptedData encryptElement(XMLObject xmlObject, EncryptionParameters encParams, + KeyEncryptionParameters kekParams) throws EncryptionException { + List kekParamsList = new ArrayList(); + kekParamsList.add(kekParams); + return encryptElement(xmlObject, encParams, kekParamsList, false); + } + + /** + * Encrypts the DOM representation of the XMLObject, encrypts the encryption key using the specified key encryption + * parameters and places the resulting EncryptedKey(s) within the EncryptedData's KeyInfo. + * + * @param xmlObject the XMLObject to be encrypted + * @param encParams parameters for encrypting the data + * @param kekParamsList parameters for encrypting the encryption key + * + * @return the resulting EncryptedData element + * @throws EncryptionException exception thrown on encryption errors + */ + public EncryptedData encryptElement(XMLObject xmlObject, EncryptionParameters encParams, + List kekParamsList) throws EncryptionException { + return encryptElement(xmlObject, encParams, kekParamsList, false); + } + + /** + * Encrypts the DOM representation of the content of an XMLObject. + * + * @param xmlObject the XMLObject to be encrypted + * @param encParams parameters for encrypting the data + * + * @return the resulting EncryptedData element + * @throws EncryptionException exception thrown on encryption errors + */ + public EncryptedData encryptElementContent(XMLObject xmlObject, EncryptionParameters encParams) + throws EncryptionException { + List emptyKEKParamsList = new ArrayList(); + return encryptElement(xmlObject, encParams, emptyKEKParamsList, true); + } + + /** + * Encrypts the DOM representation of the content of an XMLObject, encrypts the encryption key using the specified + * key encryption parameters and places the resulting EncryptedKey within the EncryptedData's KeyInfo.. + * + * @param xmlObject the XMLObject to be encrypted + * @param encParams parameters for encrypting the data + * @param kekParams parameters for encrypting the encryption key + * + * @return the resulting EncryptedData element + * @throws EncryptionException exception thrown on encryption errors + */ + public EncryptedData encryptElementContent(XMLObject xmlObject, EncryptionParameters encParams, + KeyEncryptionParameters kekParams) throws EncryptionException { + List kekParamsList = new ArrayList(); + kekParamsList.add(kekParams); + return encryptElement(xmlObject, encParams, kekParamsList, true); + } + + /** + * Encrypts the DOM representation of the content of an XMLObject, encrypts the encryption key using the specified + * key encryption parameters and places the resulting EncryptedKey(s) within the EncryptedData's KeyInfo.. + * + * @param xmlObject the XMLObject to be encrypted + * @param encParams parameters for encrypting the data + * @param kekParamsList parameters for encrypting the encryption key + * + * @return the resulting EncryptedData element + * @throws EncryptionException exception thrown on encryption errors + */ + public EncryptedData encryptElementContent(XMLObject xmlObject, EncryptionParameters encParams, + List kekParamsList) throws EncryptionException { + return encryptElement(xmlObject, encParams, kekParamsList, true); + } + + /** + * Encrypts a key once for each key encryption parameters set that is supplied. + * + * @param key the key to encrypt + * @param kekParamsList a list parameters for encrypting the key + * @param containingDocument the document that will own the DOM element underlying the resulting EncryptedKey + * objects + * + * @return the resulting list of EncryptedKey objects + * + * @throws EncryptionException exception thrown on encryption errors + */ + public List encryptKey(Key key, List kekParamsList, + Document containingDocument) throws EncryptionException { + + checkParams(kekParamsList, false); + + List encKeys = new ArrayList(); + + for (KeyEncryptionParameters kekParam : kekParamsList) { + encKeys.add(encryptKey(key, kekParam, containingDocument)); + } + return encKeys; + } + + /** + * Encrypts a key. + * + * @param key the key to encrypt + * @param kekParams parameters for encrypting the key + * @param containingDocument the document that will own the DOM element underlying the resulting EncryptedKey object + * + * @return the resulting EncryptedKey object + * + * @throws EncryptionException exception thrown on encryption errors + */ + public EncryptedKey encryptKey(Key key, KeyEncryptionParameters kekParams, Document containingDocument) + throws EncryptionException { + + checkParams(kekParams, false); + + Key encryptionKey = SecurityHelper.extractEncryptionKey(kekParams.getEncryptionCredential()); + String encryptionAlgorithmURI = kekParams.getAlgorithm(); + + EncryptedKey encryptedKey = encryptKey(key, encryptionKey, encryptionAlgorithmURI, containingDocument); + + if (kekParams.getKeyInfoGenerator() != null) { + KeyInfoGenerator generator = kekParams.getKeyInfoGenerator(); + log.debug("Dynamically generating KeyInfo from Credential for EncryptedKey using generator: {}", + generator.getClass().getName()); + try { + encryptedKey.setKeyInfo(generator.generate(kekParams.getEncryptionCredential())); + } catch (SecurityException e) { + log.error("Error during EncryptedKey KeyInfo generation", e); + throw new EncryptionException("Error during EncryptedKey KeyInfo generation", e); + } + } + + if (kekParams.getRecipient() != null) { + encryptedKey.setRecipient(kekParams.getRecipient()); + } + + return encryptedKey; + } + + /** + * Encrypts a key using the specified encryption key and algorithm URI. + * + * @param targetKey the key to encrypt + * @param encryptionKey the key with which to encrypt the target key + * @param encryptionAlgorithmURI the XML Encryption algorithm URI corresponding to the encryption key + * @param containingDocument the document that will own the resulting element + * @return the new EncryptedKey object + * @throws EncryptionException exception thrown on encryption errors + */ + protected EncryptedKey encryptKey(Key targetKey, Key encryptionKey, String encryptionAlgorithmURI, + Document containingDocument) throws EncryptionException { + + if (targetKey == null) { + log.error("Target key for key encryption was null"); + throw new EncryptionException("Target key was null"); + } + if (encryptionKey == null) { + log.error("Encryption key for key encryption was null"); + throw new EncryptionException("Encryption key was null"); + } + + log.debug("Encrypting encryption key with algorithm: {}", encryptionAlgorithmURI); + XMLCipher xmlCipher; + try { + if (getJCAProviderName() != null) { + xmlCipher = XMLCipher.getProviderInstance(encryptionAlgorithmURI, getJCAProviderName()); + } else { + xmlCipher = XMLCipher.getInstance(encryptionAlgorithmURI); + } + xmlCipher.init(XMLCipher.WRAP_MODE, encryptionKey); + } catch (XMLEncryptionException e) { + log.error("Error initializing cipher instance on key encryption", e); + throw new EncryptionException("Error initializing cipher instance on key encryption", e); + } + + org.apache.xml.security.encryption.EncryptedKey apacheEncryptedKey; + try { + apacheEncryptedKey = xmlCipher.encryptKey(containingDocument, targetKey); + postProcessApacheEncryptedKey(apacheEncryptedKey, targetKey, encryptionKey, + encryptionAlgorithmURI, containingDocument); + } catch (XMLEncryptionException e) { + log.error("Error encrypting element on key encryption", e); + throw new EncryptionException("Error encrypting element on key encryption", e); + } + + EncryptedKey encryptedKey; + try { + Element encKeyElement = xmlCipher.martial(containingDocument, apacheEncryptedKey); + encryptedKey = (EncryptedKey) encryptedKeyUnmarshaller.unmarshall(encKeyElement); + } catch (UnmarshallingException e) { + log.error("Error unmarshalling EncryptedKey element", e); + throw new EncryptionException("Error unmarshalling EncryptedKey element"); + } + + return encryptedKey; + } + + /** + * + * Post-process the Apache EncryptedKey, prior to marshalling to DOM and unmarshalling into an XMLObject. + * + * @param apacheEncryptedKey the Apache EncryptedKeyObject to post-process + * @param targetKey the key to encrypt + * @param encryptionKey the key with which to encrypt the target key + * @param encryptionAlgorithmURI the XML Encryption algorithm URI corresponding to the encryption key + * @param containingDocument the document that will own the resulting element + * + * @throws EncryptionException exception thrown on encryption errors + */ + protected void postProcessApacheEncryptedKey(org.apache.xml.security.encryption.EncryptedKey apacheEncryptedKey, + Key targetKey, Key encryptionKey, String encryptionAlgorithmURI, Document containingDocument) + throws EncryptionException { + + // Workaround for XML-Security library issue. To maximize interop, explicitly express the library + // default of SHA-1 digest method input parameter to RSA-OAEP key transport algorithm. + // Check and only add if the library hasn't already done so, which it currently doesn't. + if (EncryptionConstants.ALGO_ID_KEYTRANSPORT_RSAOAEP.equals(encryptionAlgorithmURI)) { + boolean sawDigestMethod = false; + Iterator childIter = apacheEncryptedKey.getEncryptionMethod().getEncryptionMethodInformation(); + while (childIter.hasNext()) { + Element child = (Element) childIter.next(); + if (DigestMethod.DEFAULT_ELEMENT_NAME.equals(XMLHelper.getNodeQName(child))) { + sawDigestMethod = true; + break; + } + } + if (! sawDigestMethod) { + Element digestMethodElem = XMLHelper.constructElement(containingDocument, + DigestMethod.DEFAULT_ELEMENT_NAME); + XMLHelper.appendNamespaceDeclaration(digestMethodElem, + XMLConstants.XMLSIG_NS, XMLConstants.XMLSIG_PREFIX); + digestMethodElem.setAttributeNS(null, DigestMethod.ALGORITHM_ATTRIB_NAME, + SignatureConstants.ALGO_ID_DIGEST_SHA1); + apacheEncryptedKey.getEncryptionMethod().addEncryptionMethodInformation(digestMethodElem); + } + } + + } + + /** + * Encrypts the given XMLObject using the specified encryption key, algorithm URI and content mode flag. + * + * @param xmlObject the XMLObject to be encrypted + * @param encryptionKey the key with which to encrypt the XMLObject + * @param encryptionAlgorithmURI the XML Encryption algorithm URI corresponding to the encryption key + * @param encryptContentMode whether just the content of the XMLObject should be encrypted + * @return the resulting EncryptedData object + * @throws EncryptionException exception thrown on encryption errors + */ + protected EncryptedData encryptElement(XMLObject xmlObject, Key encryptionKey, String encryptionAlgorithmURI, + boolean encryptContentMode) throws EncryptionException { + + if (xmlObject == null) { + log.error("XMLObject for encryption was null"); + throw new EncryptionException("XMLObject was null"); + } + if (encryptionKey == null) { + log.error("Encryption key for key encryption was null"); + throw new EncryptionException("Encryption key was null"); + } + log.debug("Encrypting XMLObject using algorithm URI {} with content mode {}", encryptionAlgorithmURI, + encryptContentMode); + + checkAndMarshall(xmlObject); + + Element targetElement = xmlObject.getDOM(); + Document ownerDocument = targetElement.getOwnerDocument(); + + XMLCipher xmlCipher; + try { + if (getJCAProviderName() != null) { + xmlCipher = XMLCipher.getProviderInstance(encryptionAlgorithmURI, getJCAProviderName()); + } else { + xmlCipher = XMLCipher.getInstance(encryptionAlgorithmURI); + } + xmlCipher.init(XMLCipher.ENCRYPT_MODE, encryptionKey); + } catch (XMLEncryptionException e) { + log.error("Error initializing cipher instance on XMLObject encryption", e); + throw new EncryptionException("Error initializing cipher instance", e); + } + + org.apache.xml.security.encryption.EncryptedData apacheEncryptedData; + try { + apacheEncryptedData = xmlCipher.encryptData(ownerDocument, targetElement, encryptContentMode); + } catch (Exception e) { + log.error("Error encrypting XMLObject", e); + throw new EncryptionException("Error encrypting XMLObject", e); + } + + EncryptedData encryptedData; + try { + Element encDataElement = xmlCipher.martial(ownerDocument, apacheEncryptedData); + encryptedData = (EncryptedData) encryptedDataUnmarshaller.unmarshall(encDataElement); + } catch (UnmarshallingException e) { + log.error("Error unmarshalling EncryptedData element", e); + throw new EncryptionException("Error unmarshalling EncryptedData element", e); + } + + return encryptedData; + } + + /** + * Encrypts the given XMLObject using the specified encryption key, algorithm URI and content mode flag. + * EncryptedKeys, if any, are placed inline within the KeyInfo of the resulting EncryptedData. + * + * @param xmlObject the XMLObject to be encrypted + * @param encParams the encryption parameters to use + * @param kekParamsList the key encryption parameters to use + * @param encryptContentMode whether just the content of the XMLObject should be encrypted + * + * @return the resulting EncryptedData object + * @throws EncryptionException exception thrown on encryption errors + */ + private EncryptedData encryptElement(XMLObject xmlObject, EncryptionParameters encParams, + List kekParamsList, boolean encryptContentMode) throws EncryptionException { + + checkParams(encParams, kekParamsList); + + String encryptionAlgorithmURI = encParams.getAlgorithm(); + Key encryptionKey = SecurityHelper.extractEncryptionKey(encParams.getEncryptionCredential()); + if (encryptionKey == null) { + encryptionKey = generateEncryptionKey(encryptionAlgorithmURI); + } + + EncryptedData encryptedData = encryptElement(xmlObject, encryptionKey, encryptionAlgorithmURI, + encryptContentMode); + Document ownerDocument = encryptedData.getDOM().getOwnerDocument(); + + if (encParams.getKeyInfoGenerator() != null) { + KeyInfoGenerator generator = encParams.getKeyInfoGenerator(); + log.debug("Dynamically generating KeyInfo from Credential for EncryptedData using generator: {}", + generator.getClass().getName()); + try { + encryptedData.setKeyInfo(generator.generate(encParams.getEncryptionCredential())); + } catch (SecurityException e) { + log.error("Error during EncryptedData KeyInfo generation", e); + throw new EncryptionException("Error during EncryptedData KeyInfo generation", e); + } + } + + for (KeyEncryptionParameters kekParams : kekParamsList) { + EncryptedKey encryptedKey = encryptKey(encryptionKey, kekParams, ownerDocument); + if (encryptedData.getKeyInfo() == null) { + KeyInfo keyInfo = keyInfoBuilder.buildObject(); + encryptedData.setKeyInfo(keyInfo); + } + encryptedData.getKeyInfo().getEncryptedKeys().add(encryptedKey); + } + + return encryptedData; + } + + /** + * Ensure that the XMLObject is marshalled. + * + * @param xmlObject the object to check and marshall + * @throws EncryptionException thrown if there is an error when marshalling the XMLObject + */ + protected void checkAndMarshall(XMLObject xmlObject) throws EncryptionException { + Element targetElement = xmlObject.getDOM(); + if (targetElement == null) { + Marshaller marshaller = Configuration.getMarshallerFactory().getMarshaller(xmlObject); + try { + targetElement = marshaller.marshall(xmlObject); + } catch (MarshallingException e) { + log.error("Error marshalling target XMLObject", e); + throw new EncryptionException("Error marshalling target XMLObject", e); + } + } + } + + /** + * Check data encryption parameters for consistency and required values. + * + * @param encParams the data encryption parameters to check + * + * @throws EncryptionException thrown if any parameters are missing or have invalid values + */ + protected void checkParams(EncryptionParameters encParams) throws EncryptionException { + if (encParams == null) { + log.error("Data encryption parameters are required"); + throw new EncryptionException("Data encryption parameters are required"); + } + if (DatatypeHelper.isEmpty(encParams.getAlgorithm())) { + log.error("Data encryption algorithm URI is required"); + throw new EncryptionException("Data encryption algorithm URI is required"); + } + } + + /** + * Check key encryption parameters for consistency and required values. + * + * @param kekParams the key encryption parameters to check + * @param allowEmpty if false, a null parameter is treated as an error + * + * @throws EncryptionException thrown if any parameters are missing or have invalid values + */ + protected void checkParams(KeyEncryptionParameters kekParams, boolean allowEmpty) throws EncryptionException { + if (kekParams == null) { + if (allowEmpty) { + return; + } else { + log.error("Key encryption parameters are required"); + throw new EncryptionException("Key encryption parameters are required"); + } + } + Key key = SecurityHelper.extractEncryptionKey(kekParams.getEncryptionCredential()); + if (key == null) { + log.error("Key encryption credential and contained key are required"); + throw new EncryptionException("Key encryption credential and contained key are required"); + } + if (key instanceof DSAPublicKey) { + log.error("Attempt made to use DSA key for encrypted key transport"); + throw new EncryptionException("DSA keys may not be used for encrypted key transport"); + } + if (DatatypeHelper.isEmpty(kekParams.getAlgorithm())) { + log.error("Key encryption algorithm URI is required"); + throw new EncryptionException("Key encryption algorithm URI is required"); + } + } + + /** + * Check a list of key encryption parameters for consistency and required values. + * + * @param kekParamsList the key encryption parameters list to check + * @param allowEmpty if false, a null or empty list is treated as an error + * + * @throws EncryptionException thrown if any parameters are missing or have invalid values + */ + protected void checkParams(List kekParamsList, boolean allowEmpty) + throws EncryptionException { + if (kekParamsList == null || kekParamsList.isEmpty()) { + if (allowEmpty) { + return; + } else { + log.error("Key encryption parameters list may not be empty"); + throw new EncryptionException("Key encryption parameters list may not be empty"); + } + } + for (KeyEncryptionParameters kekParams : kekParamsList) { + checkParams(kekParams, false); + } + } + + /** + * Check the encryption parameters and key encryption parameters for valid combinations of options. + * + * @param encParams the encryption parameters to use + * @param kekParamsList the key encryption parameters to use + * @throws EncryptionException exception thrown on encryption errors + */ + protected void checkParams(EncryptionParameters encParams, List kekParamsList) + throws EncryptionException { + + checkParams(encParams); + checkParams(kekParamsList, true); + + if (SecurityHelper.extractEncryptionKey(encParams.getEncryptionCredential()) == null + && (kekParamsList == null || kekParamsList.isEmpty())) { + log.error("Using a generated encryption key requires a KeyEncryptionParameters " + + "object and key encryption key"); + throw new EncryptionException("Using a generated encryption key requires a KeyEncryptionParameters " + + "object and key encryption key"); + } + } + + /** + * Generate a random symmetric encryption key. + * + * @param encryptionAlgorithmURI the encryption algorithm URI + * @return a randomly generated symmetric key + * @throws EncryptionException thrown if the key can not be generated based on the specified algorithm URI + */ + protected SecretKey generateEncryptionKey(String encryptionAlgorithmURI) throws EncryptionException { + try { + log.debug("Generating random symmetric data encryption key from algorithm URI: {}", + encryptionAlgorithmURI); + return SecurityHelper.generateSymmetricKey(encryptionAlgorithmURI); + } catch (NoSuchAlgorithmException e) { + log.error("Could not generate encryption key, algorithm URI was invalid: " + encryptionAlgorithmURI); + throw new EncryptionException("Could not generate encryption key, algorithm URI was invalid: " + + encryptionAlgorithmURI); + } catch (KeyException e) { + log.error("Could not generate encryption key from algorithm URI: " + encryptionAlgorithmURI); + throw new EncryptionException("Could not generate encryption key from algorithm URI: " + + encryptionAlgorithmURI); + } + } + + /* + * Initialize the Apache XML security library if it hasn't been already + */ + static { + if (!Init.isInitialized()) { + Init.init(); + } + } + +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/EncryptionConstants.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/EncryptionConstants.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/EncryptionConstants.java 17 Aug 2012 15:16:58 -0000 1.1 @@ -0,0 +1,103 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption; + +import org.opensaml.xml.util.XMLConstants; + +/** + * Constants defined in or related to the XML Encryption specification, version 20021210. + */ +public class EncryptionConstants { + + // ********************************************************* + // URI values which represent type attribute values + // ********************************************************* + /** URI for Content. */ + public static final String TYPE_CONTENT = XMLConstants.XMLENC_NS + "Content"; + + /** URI for Element. */ + public static final String TYPE_ELEMENT = XMLConstants.XMLENC_NS + "Element"; + + /** URI for EncryptionProperties. */ + public static final String TYPE_ENCRYPTION_PROPERTIES = XMLConstants.XMLENC_NS + "EncryptionProperties"; + + /** URI for EncryptedKey. */ + public static final String TYPE_ENCRYPTED_KEY = XMLConstants.XMLENC_NS + "EncryptedKey"; + + /** URI for DHKeyValue. */ + public static final String TYPE_KEYINFO_DH_KEYVALUE = XMLConstants.XMLENC_NS + "DHKeyValue"; + + + // ************************************************* + // Block encryption algorithms + // ************************************************* + /** Block Encryption - REQUIRED TRIPLEDES. */ + public static final String ALGO_ID_BLOCKCIPHER_TRIPLEDES = XMLConstants.XMLENC_NS + "tripledes-cbc"; + + /** Block Encryption - REQUIRED AES-128. */ + public static final String ALGO_ID_BLOCKCIPHER_AES128 = XMLConstants.XMLENC_NS + "aes128-cbc"; + + /** Block Encryption - REQUIRED AES-256. */ + public static final String ALGO_ID_BLOCKCIPHER_AES256 = XMLConstants.XMLENC_NS + "aes256-cbc"; + + /** Block Encryption - OPTIONAL AES-192. */ + public static final String ALGO_ID_BLOCKCIPHER_AES192 = XMLConstants.XMLENC_NS + "aes192-cbc"; + + // ************************************************* + // Key Transport + // ************************************************* + /** Key Transport - REQUIRED RSA-v1.5. */ + public static final String ALGO_ID_KEYTRANSPORT_RSA15 = XMLConstants.XMLENC_NS + "rsa-1_5"; + + /** Key Transport - REQUIRED RSA-OAEP. */ + public static final String ALGO_ID_KEYTRANSPORT_RSAOAEP = XMLConstants.XMLENC_NS + "rsa-oaep-mgf1p"; + + // ************************************************* + // Key Agreement + // ************************************************* + /** Key Agreement - OPTIONAL Diffie-Hellman. */ + public static final String ALGO_ID_KEYAGREEMENT_DH = XMLConstants.XMLENC_NS + "dh"; + + // ************************************************* + // Symmetric Key Wrap + // ************************************************* + /** Symmetric Key Wrap - REQUIRED TRIPLEDES KeyWrap. */ + public static final String ALGO_ID_KEYWRAP_TRIPLEDES = XMLConstants.XMLENC_NS + "kw-tripledes"; + + /** Symmetric Key Wrap - REQUIRED AES-128 KeyWrap. */ + public static final String ALGO_ID_KEYWRAP_AES128 = XMLConstants.XMLENC_NS + "kw-aes128"; + + /** Symmetric Key Wrap - REQUIRED AES-256 KeyWrap. */ + public static final String ALGO_ID_KEYWRAP_AES256 = XMLConstants.XMLENC_NS + "kw-aes256"; + + /** Symmetric Key Wrap - OPTIONAL AES-192 KeyWrap. */ + public static final String ALGO_ID_KEYWRAP_AES192 = XMLConstants.XMLENC_NS + "kw-aes192"; + + // ************************************************* + // Message Digest + // ************************************************* + /** Message Digest - RECOMMENDED SHA256. */ + public static final String ALGO_ID_DIGEST_SHA256 = XMLConstants.XMLENC_NS + "sha256"; + + /** Message Digest - OPTIONAL SHA512. */ + public static final String ALGO_ID_DIGEST_SHA512 = XMLConstants.XMLENC_NS + "sha512"; + + /** Message Digest - OPTIONAL RIPEMD-160. */ + public static final String ALGO_ID_DIGEST_RIPEMD160 = XMLConstants.XMLENC_NS + "ripemd160"; + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/EncryptionException.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/EncryptionException.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/EncryptionException.java 17 Aug 2012 15:16:58 -0000 1.1 @@ -0,0 +1,66 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption; + +/** + * Exception thrown when an error occurs during encryption operations. + */ +public class EncryptionException extends Exception { + + /** + * Serial version UID. + */ + private static final long serialVersionUID = -3196546983060216532L; + + /** + * Constructor. + */ + public EncryptionException() { + super(); + } + + /** + * Constructor. + * + * @param message exception message + */ + public EncryptionException(String message) { + super(message); + } + + /** + * Constructor. + * + * @param wrappedException exception to be wrapped by this one + */ + public EncryptionException(Exception wrappedException) { + super(wrappedException); + } + + /** + * Constructor. + * + * @param message exception message + * @param wrappedException exception to be wrapped by this one + */ + public EncryptionException(String message, Exception wrappedException) { + super(message, wrappedException); + } + + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/EncryptionMethod.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/EncryptionMethod.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/EncryptionMethod.java 17 Aug 2012 15:16:58 -0000 1.1 @@ -0,0 +1,92 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption; + + +import javax.xml.namespace.QName; + +import org.opensaml.xml.ElementExtensibleXMLObject; +import org.opensaml.xml.util.XMLConstants; +import org.opensaml.xml.validation.ValidatingXMLObject; + +/** + * XMLObject representing XML Encryption, version 20021210, EncryptionMethod element. + */ +public interface EncryptionMethod extends ValidatingXMLObject, ElementExtensibleXMLObject { + + /** Element local name. */ + public static final String DEFAULT_ELEMENT_LOCAL_NAME = "EncryptionMethod"; + + /** Default element name. */ + public static final QName DEFAULT_ELEMENT_NAME = new QName(XMLConstants.XMLENC_NS, DEFAULT_ELEMENT_LOCAL_NAME, + XMLConstants.XMLENC_PREFIX); + + /** Local name of the XSI type. */ + public static final String TYPE_LOCAL_NAME = "EncryptionMethodType"; + + /** QName of the XSI type. */ + public static final QName TYPE_NAME = new QName(XMLConstants.XMLENC_NS, TYPE_LOCAL_NAME, + XMLConstants.XMLENC_PREFIX); + + /** Algorithm attribute name. */ + public static final String ALGORITHM_ATTRIB_NAME = "Algorithm"; + + + /** + * Gets the algorithm URI attribute used in this EncryptionMethod. + * + * @return the Algorithm attribute URI attribute string + */ + public String getAlgorithm(); + + /** + * Sets the algorithm URI attribute used in this EncryptionMethod. + * + * @param newAlgorithm the new Algorithm URI attribute string + */ + public void setAlgorithm(String newAlgorithm); + + /** + * Gets the KeySize child element. + * + * @return the KeySize child element + */ + public KeySize getKeySize(); + + /** + * Sets the KeySize child element. + * + * @param newKeySize the new KeySize child element + */ + public void setKeySize(KeySize newKeySize); + + /** + * Gets the OAEPparams child element. + * + * @return the OAEPparams child element + */ + public OAEPparams getOAEPparams(); + + /** + * Sets the OAEPparams child element. + * + * @param newOAEPparams the new OAEPparams child element + */ + public void setOAEPparams(OAEPparams newOAEPparams); + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/EncryptionParameters.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/EncryptionParameters.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/EncryptionParameters.java 17 Aug 2012 15:16:59 -0000 1.1 @@ -0,0 +1,101 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption; + +import org.opensaml.xml.security.credential.Credential; +import org.opensaml.xml.security.keyinfo.KeyInfoGenerator; + +/** + * Parameters for encrypting XMLObjects. + */ +public class EncryptionParameters { + + /** Credential used to encrypt. */ + private Credential encryptionCredential; + + /** XML Encryption algorithm URI used to encrypt. */ + private String algorithm; + + /** Generator for dynamically generating a KeyInfo instance containing information + * from the encryption credential. */ + private KeyInfoGenerator keyInfoGenerator; + + /** + * Constructor. + */ + public EncryptionParameters() { + // This will be the default for auto encryption key generation + setAlgorithm(EncryptionConstants.ALGO_ID_BLOCKCIPHER_AES256); + } + + /** + * Gets the XML Encryption algorithm URI used to encrypt. + * + * @return the algorithm URI used to encrypt + */ + public String getAlgorithm() { + return this.algorithm; + } + + /** + * Sets the XML Encryption algorithm URI used to encrypt. + * + * @param newAlgorithm the algorithm URI used to encrypt + */ + public void setAlgorithm(String newAlgorithm) { + this.algorithm = newAlgorithm; + } + + /** + * Gets the credential used to encrypt. + * + * @return the credential used to encrypt + */ + public Credential getEncryptionCredential() { + return this.encryptionCredential; + } + + /** + * Sets the credential used to encrypt. + * + * @param newEncryptionCredential the credential used to encrypt + */ + public void setEncryptionCredential(Credential newEncryptionCredential) { + this.encryptionCredential = newEncryptionCredential; + } + + /** + * Gets the instance which will be used to generate a KeyInfo + * object from the encryption credential. + * + * @return the generator instance + */ + public KeyInfoGenerator getKeyInfoGenerator() { + return this.keyInfoGenerator; + } + + /** + * Sets the instance which will be used to generate a KeyInfo + * object from the encryption credential. + * + * @param newKeyInfoGenerator the new generator instance + */ + public void setKeyInfoGenerator(KeyInfoGenerator newKeyInfoGenerator) { + this.keyInfoGenerator = newKeyInfoGenerator; + } +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/EncryptionProperties.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/EncryptionProperties.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/EncryptionProperties.java 17 Aug 2012 15:16:58 -0000 1.1 @@ -0,0 +1,70 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption; + +import java.util.List; + +import javax.xml.namespace.QName; + +import org.opensaml.xml.util.XMLConstants; +import org.opensaml.xml.validation.ValidatingXMLObject; + +/** + * XMLObject representing XML Encryption, version 20021210, EncryptionProperties element. + */ +public interface EncryptionProperties extends ValidatingXMLObject { + + /** Element local name. */ + public static final String DEFAULT_ELEMENT_LOCAL_NAME = "EncryptionProperties"; + + /** Default element name. */ + public static final QName DEFAULT_ELEMENT_NAME = new QName(XMLConstants.XMLENC_NS, DEFAULT_ELEMENT_LOCAL_NAME, + XMLConstants.XMLENC_PREFIX); + + /** Local name of the XSI type. */ + public static final String TYPE_LOCAL_NAME = "EncryptionPropertiesType"; + + /** QName of the XSI type. */ + public static final QName TYPE_NAME = new QName(XMLConstants.XMLENC_NS, TYPE_LOCAL_NAME, + XMLConstants.XMLENC_PREFIX); + + /** ID attribute name. */ + public static final String ID_ATTRIB_NAME = "Id"; + + /** + * Get the ID attribute that uniquely identifies this element. + * + * @return ID attribute + */ + public String getID(); + + /** + * Set the ID attribute that uniquely identifies this element. + * + * @param newID the new ID attribute value + */ + public void setID(String newID); + + /** + * Get the list of EncryptionProperty child elements. + * + * @return the List of EncryptionProperty child elements + */ + public List getEncryptionProperties(); + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/EncryptionProperty.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/EncryptionProperty.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/EncryptionProperty.java 17 Aug 2012 15:16:58 -0000 1.1 @@ -0,0 +1,81 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption; + +import javax.xml.namespace.QName; + +import org.opensaml.xml.AttributeExtensibleXMLObject; +import org.opensaml.xml.ElementExtensibleXMLObject; +import org.opensaml.xml.util.XMLConstants; +import org.opensaml.xml.validation.ValidatingXMLObject; + +/** + * XMLObject representing XML Encryption, version 20021210, EncryptionProperty element. + */ +public interface EncryptionProperty extends ValidatingXMLObject, AttributeExtensibleXMLObject, + ElementExtensibleXMLObject { + + /** Element local name. */ + public static final String DEFAULT_ELEMENT_LOCAL_NAME = "EncryptionProperty"; + + /** Default element name. */ + public static final QName DEFAULT_ELEMENT_NAME = new QName(XMLConstants.XMLENC_NS, DEFAULT_ELEMENT_LOCAL_NAME, + XMLConstants.XMLENC_PREFIX); + + /** Local name of the XSI type. */ + public static final String TYPE_LOCAL_NAME = "EncryptionPropertyType"; + + /** QName of the XSI type. */ + public static final QName TYPE_NAME = new QName(XMLConstants.XMLENC_NS, TYPE_LOCAL_NAME, + XMLConstants.XMLENC_PREFIX); + + /** Target attribute name. */ + public static final String TARGET_ATTRIB_NAME = "Target"; + + /** Id attribute name. */ + public static final String ID_ATTRIB_NAME = "Id"; + + /** + * Get the target URI attribute which specifies to which element this. property applies + * + * @return the target URI attribute + */ + public String getTarget(); + + /** + * Set the target URI attribute which specifies to which element this property applies. + * + * @param newTarget the new target URI attribute + */ + public void setTarget(String newTarget); + + /** + * Get the ID attribute which uniquely identifies this element. + * + * @return the ID attribute value + */ + public String getID(); + + /** + * Set the ID attribute which uniquely identifies this element. + * + * @param newID the new ID attribute + */ + public void setID(String newID); + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/Generator.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/Generator.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/Generator.java 17 Aug 2012 15:16:58 -0000 1.1 @@ -0,0 +1,38 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption; + +import javax.xml.namespace.QName; + +import org.opensaml.xml.signature.CryptoBinary; +import org.opensaml.xml.util.XMLConstants; + +/** + * XMLObject representing XML Encryption, version 20021210, Generator element. + */ +public interface Generator extends CryptoBinary { + + /** Element local name. */ + public static final String DEFAULT_ELEMENT_LOCAL_NAME = "Generator"; + + /** Default element name. */ + public static final QName DEFAULT_ELEMENT_NAME = new QName(XMLConstants.XMLENC_NS, DEFAULT_ELEMENT_LOCAL_NAME, + XMLConstants.XMLENC_PREFIX); + + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/InlineEncryptedKeyResolver.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/InlineEncryptedKeyResolver.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/InlineEncryptedKeyResolver.java 17 Aug 2012 15:16:57 -0000 1.1 @@ -0,0 +1,46 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption; + +import java.util.ArrayList; +import java.util.List; + +/** + * Implementation of {@link EncryptedKeyResolver} which finds {@link EncryptedKey} elements + * within the {@link org.opensaml.xml.signature.KeyInfo} of the {@link EncryptedData} context. + */ +public class InlineEncryptedKeyResolver extends AbstractEncryptedKeyResolver { + + /** {@inheritDoc} */ + public Iterable resolve(EncryptedData encryptedData) { + List resolvedEncKeys = new ArrayList(); + + if (encryptedData.getKeyInfo() == null) { + return resolvedEncKeys; + } + + for (EncryptedKey encKey : encryptedData.getKeyInfo().getEncryptedKeys()) { + if (matchRecipient(encKey.getRecipient())) { + resolvedEncKeys.add(encKey); + } + } + + return resolvedEncKeys; + } + +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/KANonce.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/KANonce.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/KANonce.java 17 Aug 2012 15:16:58 -0000 1.1 @@ -0,0 +1,37 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption; + +import javax.xml.namespace.QName; + +import org.opensaml.xml.schema.XSBase64Binary; +import org.opensaml.xml.util.XMLConstants; + +/** + * XMLObject representing XML Encryption, version 20021210, KA-Nonce element. + */ +public interface KANonce extends XSBase64Binary { + + /** Element local name. */ + public static final String DEFAULT_ELEMENT_LOCAL_NAME = "KA-Nonce"; + + /** Default element name. */ + public static final QName DEFAULT_ELEMENT_NAME = new QName(XMLConstants.XMLENC_NS, DEFAULT_ELEMENT_LOCAL_NAME, + XMLConstants.XMLENC_PREFIX); + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/KeyEncryptionParameters.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/KeyEncryptionParameters.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/KeyEncryptionParameters.java 17 Aug 2012 15:16:58 -0000 1.1 @@ -0,0 +1,61 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption; + + +/** + * Parameters for encrypting keys. + */ +public class KeyEncryptionParameters extends EncryptionParameters { + + /** Recipient of the key. */ + private String recipient; + + /** + * Constructor. + */ + public KeyEncryptionParameters() { + super(); + // The default supplied by the super class doesn't make sense, + // can't autogenerate a key encryption key, always needs to be derived + // from the key in the (for KEK, mandatory) encryption credential. + setAlgorithm(null); + } + + /** + * Gets the recipient of the key. + * + * When generating an EncryptedKey, this will be used as the value of the Recipient attribute. + * + * @return the recipient of the key + */ + public String getRecipient() { + return recipient; + } + + /** + * Sets the recipient of the key. + * + * When generating an EncryptedKey, this will be used as the value of the Recipient attribute. + * + * @param newRecipient the recipient of the key + */ + public void setRecipient(String newRecipient) { + this.recipient = newRecipient; + } +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/KeyReference.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/KeyReference.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/KeyReference.java 17 Aug 2012 15:16:59 -0000 1.1 @@ -0,0 +1,37 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption; + +import javax.xml.namespace.QName; + +import org.opensaml.xml.util.XMLConstants; + + +/** + * XMLObject representing XML Encryption, version 20021210, KeyReference element. + */ +public interface KeyReference extends ReferenceType { + + /** Element local name. */ + public static final String DEFAULT_ELEMENT_LOCAL_NAME = "KeyReference"; + + /** Default element name. */ + public static final QName DEFAULT_ELEMENT_NAME = new QName(XMLConstants.XMLENC_NS, DEFAULT_ELEMENT_LOCAL_NAME, + XMLConstants.XMLENC_PREFIX); + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/KeySize.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/KeySize.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/KeySize.java 17 Aug 2012 15:16:57 -0000 1.1 @@ -0,0 +1,44 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption; + +import javax.xml.namespace.QName; + +import org.opensaml.xml.schema.XSInteger; +import org.opensaml.xml.util.XMLConstants; + +/** + * XMLObject representing XML Encryption, version 20021210, KeySize element. + */ +public interface KeySize extends XSInteger { + + /** Element local name. */ + public static final String DEFAULT_ELEMENT_LOCAL_NAME = "KeySize"; + + /** Default element name. */ + public static final QName DEFAULT_ELEMENT_NAME = new QName(XMLConstants.XMLENC_NS, DEFAULT_ELEMENT_LOCAL_NAME, + XMLConstants.XMLENC_PREFIX); + + /** Local name of the XSI type. */ + public static final String TYPE_LOCAL_NAME = "KeySizeType"; + + /** QName of the XSI type. */ + public static final QName TYPE_NAME = new QName(XMLConstants.XMLENC_NS, TYPE_LOCAL_NAME, + XMLConstants.XMLENC_PREFIX); + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/OAEPparams.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/OAEPparams.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/OAEPparams.java 17 Aug 2012 15:16:58 -0000 1.1 @@ -0,0 +1,37 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption; + +import javax.xml.namespace.QName; + +import org.opensaml.xml.schema.XSBase64Binary; +import org.opensaml.xml.util.XMLConstants; + +/** + * XMLObject representing XML Encryption, version 20021210, OAEPparams element. + */ +public interface OAEPparams extends XSBase64Binary { + + /** Element local name. */ + public static final String DEFAULT_ELEMENT_LOCAL_NAME = "OAEPparams"; + + /** Default element name. */ + public static final QName DEFAULT_ELEMENT_NAME = new QName(XMLConstants.XMLENC_NS, DEFAULT_ELEMENT_LOCAL_NAME, + XMLConstants.XMLENC_PREFIX); + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/OriginatorKeyInfo.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/OriginatorKeyInfo.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/OriginatorKeyInfo.java 17 Aug 2012 15:16:59 -0000 1.1 @@ -0,0 +1,37 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption; + +import javax.xml.namespace.QName; + +import org.opensaml.xml.signature.KeyInfoType; +import org.opensaml.xml.util.XMLConstants; + +/** + * XMLObject representing XML Encryption, version 20021210, OriginatorKeyInfo element. + */ +public interface OriginatorKeyInfo extends KeyInfoType { + + /** Element local name. */ + public static final String DEFAULT_ELEMENT_LOCAL_NAME = "OriginatorKeyInfo"; + + /** Default element name. */ + public static final QName DEFAULT_ELEMENT_NAME = new QName(XMLConstants.XMLENC_NS, DEFAULT_ELEMENT_LOCAL_NAME, + XMLConstants.XMLENC_PREFIX); + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/P.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/P.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/P.java 17 Aug 2012 15:16:58 -0000 1.1 @@ -0,0 +1,37 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption; + +import javax.xml.namespace.QName; + +import org.opensaml.xml.signature.CryptoBinary; +import org.opensaml.xml.util.XMLConstants; + +/** + * XMLObject representing XML Encryption, version 20021210, P element. + */ +public interface P extends CryptoBinary { + + /** Element local name. */ + public static final String DEFAULT_ELEMENT_LOCAL_NAME = "P"; + + /** Default element name. */ + public static final QName DEFAULT_ELEMENT_NAME = new QName(XMLConstants.XMLENC_NS, DEFAULT_ELEMENT_LOCAL_NAME, + XMLConstants.XMLENC_PREFIX); + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/PgenCounter.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/PgenCounter.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/PgenCounter.java 17 Aug 2012 15:16:58 -0000 1.1 @@ -0,0 +1,37 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption; + +import javax.xml.namespace.QName; + +import org.opensaml.xml.signature.CryptoBinary; +import org.opensaml.xml.util.XMLConstants; + +/** + * XMLObject representing XML Encryption, version 20021210, pgenCounter element. + */ +public interface PgenCounter extends CryptoBinary { + + /** Element local name. */ + public static final String DEFAULT_ELEMENT_LOCAL_NAME = "pgenCounter"; + + /** Default element name. */ + public static final QName DEFAULT_ELEMENT_NAME = new QName(XMLConstants.XMLENC_NS, DEFAULT_ELEMENT_LOCAL_NAME, + XMLConstants.XMLENC_PREFIX); + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/Public.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/Public.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/Public.java 17 Aug 2012 15:16:57 -0000 1.1 @@ -0,0 +1,37 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption; + +import javax.xml.namespace.QName; + +import org.opensaml.xml.signature.CryptoBinary; +import org.opensaml.xml.util.XMLConstants; + +/** + * XMLObject representing XML Encryption, version 20021210, Public element. + */ +public interface Public extends CryptoBinary { + + /** Element local name. */ + public static final String DEFAULT_ELEMENT_LOCAL_NAME = "Public"; + + /** Default element name. */ + public static final QName DEFAULT_ELEMENT_NAME = new QName(XMLConstants.XMLENC_NS, DEFAULT_ELEMENT_LOCAL_NAME, + XMLConstants.XMLENC_PREFIX); + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/Q.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/Q.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/Q.java 17 Aug 2012 15:16:58 -0000 1.1 @@ -0,0 +1,37 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption; + +import javax.xml.namespace.QName; + +import org.opensaml.xml.signature.CryptoBinary; +import org.opensaml.xml.util.XMLConstants; + +/** + * XMLObject representing XML Encryption, version 20021210, Q element. + */ +public interface Q extends CryptoBinary { + + /** Element local name. */ + public static final String DEFAULT_ELEMENT_LOCAL_NAME = "Q"; + + /** Default element name. */ + public static final QName DEFAULT_ELEMENT_NAME = new QName(XMLConstants.XMLENC_NS, DEFAULT_ELEMENT_LOCAL_NAME, + XMLConstants.XMLENC_PREFIX); + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/RecipientKeyInfo.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/RecipientKeyInfo.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/RecipientKeyInfo.java 17 Aug 2012 15:16:58 -0000 1.1 @@ -0,0 +1,38 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption; + +import javax.xml.namespace.QName; + +import org.opensaml.xml.signature.KeyInfoType; +import org.opensaml.xml.util.XMLConstants; + +/** + * XMLObject representing XML Encryption, version 20021210, RecipientKeyInfo element. + */ +public interface RecipientKeyInfo extends KeyInfoType { + + /** Element local name. */ + public static final String DEFAULT_ELEMENT_LOCAL_NAME = "RecipientKeyInfo"; + + /** Default element name. */ + public static final QName DEFAULT_ELEMENT_NAME = new QName(XMLConstants.XMLENC_NS, DEFAULT_ELEMENT_LOCAL_NAME, + XMLConstants.XMLENC_PREFIX); + + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/ReferenceList.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/ReferenceList.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/ReferenceList.java 17 Aug 2012 15:16:58 -0000 1.1 @@ -0,0 +1,62 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption; + +import java.util.List; + +import javax.xml.namespace.QName; + +import org.opensaml.xml.util.XMLConstants; +import org.opensaml.xml.validation.ValidatingXMLObject; + +/** + * XMLObject representing XML Encryption, version 20021210, ReferenceList element. + */ +public interface ReferenceList extends ValidatingXMLObject { + + /** Element local name. */ + public static final String DEFAULT_ELEMENT_LOCAL_NAME = "ReferenceList"; + + /** Default element name. */ + public static final QName DEFAULT_ELEMENT_NAME = new QName(XMLConstants.XMLENC_NS, DEFAULT_ELEMENT_LOCAL_NAME, + XMLConstants.XMLENC_PREFIX); + + /** + * Get the list of reference child elements. + * + * @return the list of reference child elements + */ + public List getReferences(); + + /** + * Get the list of data reference child elements. + * + * @return the list of data reference child elements + */ + public List getDataReferences(); + + /** + * Get the list of key reference child elements. + * + * @return the list of key reference child elements + */ + public List getKeyReferences(); + + + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/ReferenceType.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/ReferenceType.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/ReferenceType.java 17 Aug 2012 15:16:58 -0000 1.1 @@ -0,0 +1,57 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption; + +import javax.xml.namespace.QName; + +import org.opensaml.xml.ElementExtensibleXMLObject; +import org.opensaml.xml.util.XMLConstants; +import org.opensaml.xml.validation.ValidatingXMLObject; + +/** + * XMLObject representing XML Encryption, version 20021210, ReferenceType type. This is the base type for + * {@link DataReference} and {@link KeyReference} types. + */ +public interface ReferenceType extends ValidatingXMLObject, ElementExtensibleXMLObject { + + /** Local name of the XSI type. */ + public static final String TYPE_LOCAL_NAME = "ReferenceType"; + + /** QName of the XSI type. */ + public static final QName TYPE_NAME = new QName(XMLConstants.XMLENC_NS, TYPE_LOCAL_NAME, + XMLConstants.XMLENC_PREFIX); + + /** URI attribute name. */ + public static final String URI_ATTRIB_NAME = "URI"; + + /** + * Get the URI attribute which indicates the referent of this reference. + * + * @return the URI referent attribute value + */ + public String getURI(); + + /** + * Set the URI attribute which indicates the referent of this reference. + * + * @param newURI the new URI attribute value + */ + public void setURI(String newURI); + + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/Seed.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/Seed.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/Seed.java 17 Aug 2012 15:16:58 -0000 1.1 @@ -0,0 +1,37 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption; + +import javax.xml.namespace.QName; + +import org.opensaml.xml.signature.CryptoBinary; +import org.opensaml.xml.util.XMLConstants; + +/** + * XMLObject representing XML Digital Signature, version 20020212, seed element. + */ +public interface Seed extends CryptoBinary { + + /** Element local name. */ + public static final String DEFAULT_ELEMENT_LOCAL_NAME = "seed"; + + /** Default element name. */ + public static final QName DEFAULT_ELEMENT_NAME = new QName(XMLConstants.XMLENC_NS, DEFAULT_ELEMENT_LOCAL_NAME, + XMLConstants.XMLENC_PREFIX); + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/SimpleRetrievalMethodEncryptedKeyResolver.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/SimpleRetrievalMethodEncryptedKeyResolver.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/SimpleRetrievalMethodEncryptedKeyResolver.java 17 Aug 2012 15:16:58 -0000 1.1 @@ -0,0 +1,98 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption; + +import java.util.ArrayList; +import java.util.List; + +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.signature.RetrievalMethod; +import org.opensaml.xml.util.DatatypeHelper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Implementation of {@link EncryptedKeyResolver} which finds {@link EncryptedKey} elements by dereferencing + * {@link RetrievalMethod} children of the {@link org.opensaml.xml.signature.KeyInfo} of the {@link EncryptedData} + * context. + * + * The RetrievalMethod must have a Type attribute with the value of + * {@link EncryptionConstants#TYPE_ENCRYPTED_KEY}. The URI attribute value must be a same-document + * fragment identifier (via ID attribute). Processing of transforms children of RetrievalMethod is not supported by this + * implementation. + */ +public class SimpleRetrievalMethodEncryptedKeyResolver extends AbstractEncryptedKeyResolver { + + /** Class logger. */ + private final Logger log = LoggerFactory.getLogger(SimpleRetrievalMethodEncryptedKeyResolver.class); + + /** {@inheritDoc} */ + public Iterable resolve(EncryptedData encryptedData) { + List resolvedEncKeys = new ArrayList(); + + if (encryptedData.getKeyInfo() == null) { + return resolvedEncKeys; + } + + for (RetrievalMethod rm : encryptedData.getKeyInfo().getRetrievalMethods()) { + if (!DatatypeHelper.safeEquals(rm.getType(), EncryptionConstants.TYPE_ENCRYPTED_KEY)) { + continue; + } + if (rm.getTransforms() != null) { + log.warn("EncryptedKey RetrievalMethod has transforms, can not process"); + continue; + } + + EncryptedKey encKey = dereferenceURI(rm); + if (encKey == null) { + continue; + } + + if (matchRecipient(encKey.getRecipient())) { + resolvedEncKeys.add(encKey); + } + } + + return resolvedEncKeys; + } + + /** + * Dereference the URI attribute of the specified retrieval method into an EncryptedKey. + * + * @param rm the RetrievalMethod to process + * @return the dereferenced EncryptedKey + */ + protected EncryptedKey dereferenceURI(RetrievalMethod rm) { + String uri = rm.getURI(); + if (DatatypeHelper.isEmpty(uri) || !uri.startsWith("#")) { + log.warn("EncryptedKey RetrievalMethod did not contain a same-document URI reference, can not process"); + return null; + } + XMLObject target = rm.resolveIDFromRoot(uri.substring(1)); + if (target == null) { + log.warn("EncryptedKey RetrievalMethod URI could not be dereferenced"); + return null; + } + if (!(target instanceof EncryptedKey)) { + log.warn("The product of dereferencing the EncryptedKey RetrievalMethod was not an EncryptedKey"); + return null; + } + return (EncryptedKey) target; + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/Transforms.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/Transforms.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/Transforms.java 17 Aug 2012 15:16:58 -0000 1.1 @@ -0,0 +1,54 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption; + +import java.util.List; + +import javax.xml.namespace.QName; + +import org.opensaml.xml.signature.Transform; +import org.opensaml.xml.util.XMLConstants; +import org.opensaml.xml.validation.ValidatingXMLObject; + +/** + * XMLObject representing XML Encryption, version 20021210, Transforms element. + */ +public interface Transforms extends ValidatingXMLObject { + + /** Element local name. */ + public static final String DEFAULT_ELEMENT_LOCAL_NAME = "Transforms"; + + /** Default element name. */ + public static final QName DEFAULT_ELEMENT_NAME = new QName(XMLConstants.XMLENC_NS, DEFAULT_ELEMENT_LOCAL_NAME, + XMLConstants.XMLENC_PREFIX); + + /** Local name of the XSI type. */ + public static final String TYPE_LOCAL_NAME = "TransformsType"; + + /** QName of the XSI type. */ + public static final QName TYPE_NAME = new QName(XMLConstants.XMLENC_NS, TYPE_LOCAL_NAME, + XMLConstants.XMLENC_PREFIX); + + /** + * Get the list of Transform child elements. + * + * @return a List of Transform child elements + */ + public List getTransforms(); + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/XMLEncryptionBuilder.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/XMLEncryptionBuilder.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/XMLEncryptionBuilder.java 17 Aug 2012 15:16:58 -0000 1.1 @@ -0,0 +1,37 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption; + +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.XMLObjectBuilder; + +/** + * Builder for XMLObjects from {@link org.opensaml.xml.encryption}. + * + * @param the type of XMLObject being built + */ +public interface XMLEncryptionBuilder extends XMLObjectBuilder { + + /** + * Builds an XMLObject using the default name and namespace information provided XML Encryption specifications. + * + * @return built XMLObject + */ + public XMLEncryptionType buildObject(); + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/package.html =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/package.html,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/package.html 17 Aug 2012 15:16:58 -0000 1.1 @@ -0,0 +1,6 @@ + + +XMLObject interfaces and helper classes for representing encrypted content and encrypting/decrypting content. + + + \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/AbstractXMLEncryptionMarshaller.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/AbstractXMLEncryptionMarshaller.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/AbstractXMLEncryptionMarshaller.java 17 Aug 2012 15:17:11 -0000 1.1 @@ -0,0 +1,49 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption.impl; + +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.io.AbstractXMLObjectMarshaller; +import org.opensaml.xml.io.MarshallingException; +import org.w3c.dom.Element; + +/** + * An abstract marshaller implementation for XMLObjects from {@link org.opensaml.xml.encryption}. + */ +public abstract class AbstractXMLEncryptionMarshaller extends AbstractXMLObjectMarshaller { + + /** + * No-op method. Extending implementations should override this method if they have attributes to marshall into the + * Element. + * + * {@inheritDoc} + */ + protected void marshallAttributes(XMLObject xmlObject, Element domElement) throws MarshallingException { + + } + + /** + * No-op method. Extending implementations should override this method if they have text content to marshall into + * the Element. + * + * {@inheritDoc} + */ + protected void marshallElementContent(XMLObject xmlObject, Element domElement) throws MarshallingException { + + } +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/AbstractXMLEncryptionUnmarshaller.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/AbstractXMLEncryptionUnmarshaller.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/AbstractXMLEncryptionUnmarshaller.java 17 Aug 2012 15:17:12 -0000 1.1 @@ -0,0 +1,58 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption.impl; + +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.io.AbstractXMLObjectUnmarshaller; +import org.opensaml.xml.io.UnmarshallingException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.w3c.dom.Attr; + +/** + * An abstract unmarshaller implementation for XMLObjects from {@link org.opensaml.xml.encryption}. + */ +public abstract class AbstractXMLEncryptionUnmarshaller extends AbstractXMLObjectUnmarshaller { + + /** + * Logger. + */ + private final Logger log = LoggerFactory.getLogger(AbstractXMLEncryptionUnmarshaller.class); + + /** + * {@inheritDoc} + */ + protected void processChildElement(XMLObject parentXMLObject, XMLObject childXMLObject) + throws UnmarshallingException { + log.debug("Ignoring unknown element {}", childXMLObject.getElementQName()); + } + + /** + * {@inheritDoc} + */ + protected void processAttribute(XMLObject xmlObject, Attr attribute) throws UnmarshallingException { + log.debug("Ignorning unknown attribute {}", attribute.getLocalName()); + } + + /** + * {@inheritDoc} + */ + protected void processElementContent(XMLObject xmlObject, String elementContent) { + log.debug("Ignoring element content {}", elementContent); + } +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/AgreementMethodBuilder.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/AgreementMethodBuilder.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/AgreementMethodBuilder.java 17 Aug 2012 15:17:10 -0000 1.1 @@ -0,0 +1,49 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption.impl; + +import org.opensaml.xml.AbstractXMLObjectBuilder; +import org.opensaml.xml.encryption.AgreementMethod; +import org.opensaml.xml.encryption.XMLEncryptionBuilder; +import org.opensaml.xml.util.XMLConstants; + +/** + * Builder of {@link org.opensaml.xml.encryption.AgreementMethod}. + */ +public class AgreementMethodBuilder extends AbstractXMLObjectBuilder implements + XMLEncryptionBuilder { + + /** + * Constructor. + * + */ + public AgreementMethodBuilder() { + } + + /** {@inheritDoc} */ + public AgreementMethod buildObject(String namespaceURI, String localName, String namespacePrefix) { + return new AgreementMethodImpl(namespaceURI, localName, namespacePrefix); + } + + /** {@inheritDoc} */ + public AgreementMethod buildObject() { + return buildObject(XMLConstants.XMLENC_NS, AgreementMethod.DEFAULT_ELEMENT_LOCAL_NAME, + XMLConstants.XMLENC_PREFIX); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/AgreementMethodImpl.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/AgreementMethodImpl.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/AgreementMethodImpl.java 17 Aug 2012 15:17:12 -0000 1.1 @@ -0,0 +1,139 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption.impl; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import javax.xml.namespace.QName; + +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.encryption.AgreementMethod; +import org.opensaml.xml.encryption.KANonce; +import org.opensaml.xml.encryption.OriginatorKeyInfo; +import org.opensaml.xml.encryption.RecipientKeyInfo; +import org.opensaml.xml.util.IndexedXMLObjectChildrenList; +import org.opensaml.xml.validation.AbstractValidatingXMLObject; + +/** + * Concrete implementation of {@link org.opensaml.xml.encryption.AgreementMethod}. + */ +public class AgreementMethodImpl extends AbstractValidatingXMLObject implements AgreementMethod { + + /** Algorithm attribute value. */ + private String algorithm; + + /** KA-Nonce child element value. */ + private KANonce kaNonce; + + /** OriginatorKeyInfo child element value. */ + private OriginatorKeyInfo originatorKeyInfo; + + /** RecipientKeyInfo child element value. */ + private RecipientKeyInfo recipientKeyInfo; + + /** List of wildcard <any> XMLObject children. */ + private IndexedXMLObjectChildrenList xmlChildren; + + /** + * Constructor. + * + * @param namespaceURI namespace URI + * @param elementLocalName element local name + * @param namespacePrefix namespace prefix + */ + protected AgreementMethodImpl(String namespaceURI, String elementLocalName, String namespacePrefix) { + super(namespaceURI, elementLocalName, namespacePrefix); + xmlChildren = new IndexedXMLObjectChildrenList(this); + } + + /** {@inheritDoc} */ + public String getAlgorithm() { + return this.algorithm; + } + + /** {@inheritDoc} */ + public void setAlgorithm(String newAlgorithm) { + this.algorithm = prepareForAssignment(this.algorithm, newAlgorithm); + } + + /** {@inheritDoc} */ + public KANonce getKANonce() { + return this.kaNonce; + } + + /** {@inheritDoc} */ + public void setKANonce(KANonce newKANonce) { + this.kaNonce = prepareForAssignment(this.kaNonce, newKANonce); + } + + /** {@inheritDoc} */ + public OriginatorKeyInfo getOriginatorKeyInfo() { + return this.originatorKeyInfo; + } + + /** {@inheritDoc} */ + public void setOriginatorKeyInfo(OriginatorKeyInfo newOriginatorKeyInfo) { + this.originatorKeyInfo = prepareForAssignment(this.originatorKeyInfo, newOriginatorKeyInfo); + } + + /** {@inheritDoc} */ + public RecipientKeyInfo getRecipientKeyInfo() { + return this.recipientKeyInfo; + } + + /** {@inheritDoc} */ + public void setRecipientKeyInfo(RecipientKeyInfo newRecipientKeyInfo) { + this.recipientKeyInfo = prepareForAssignment(this.recipientKeyInfo, newRecipientKeyInfo); + } + + /** {@inheritDoc} */ + public List getUnknownXMLObjects() { + return (List) this.xmlChildren; + } + /** {@inheritDoc} */ + public List getUnknownXMLObjects(QName typeOrName) { + return (List) this.xmlChildren.subList(typeOrName); + } + + /** {@inheritDoc} */ + public List getOrderedChildren() { + ArrayList children = new ArrayList(); + + if (kaNonce != null) { + children.add(kaNonce); + } + + children.addAll(xmlChildren); + + if (originatorKeyInfo != null) { + children.add(originatorKeyInfo); + } + if (recipientKeyInfo != null) { + children.add(recipientKeyInfo); + } + + if (children.size() == 0) { + return null; + } + + return Collections.unmodifiableList(children); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/AgreementMethodMarshaller.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/AgreementMethodMarshaller.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/AgreementMethodMarshaller.java 17 Aug 2012 15:17:12 -0000 1.1 @@ -0,0 +1,39 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption.impl; + +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.encryption.AgreementMethod; +import org.opensaml.xml.io.MarshallingException; +import org.w3c.dom.Element; + +/** + * A thread-safe Marshaller for {@link org.opensaml.xml.encryption.AgreementMethod} objects. + */ +public class AgreementMethodMarshaller extends AbstractXMLEncryptionMarshaller { + + /** {@inheritDoc} */ + protected void marshallAttributes(XMLObject xmlObject, Element domElement) throws MarshallingException { + AgreementMethod am = (AgreementMethod) xmlObject; + + if (am.getAlgorithm() != null) { + domElement.setAttributeNS(null, AgreementMethod.ALGORITHM_ATTRIBUTE_NAME, am.getAlgorithm()); + } + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/AgreementMethodUnmarshaller.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/AgreementMethodUnmarshaller.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/AgreementMethodUnmarshaller.java 17 Aug 2012 15:17:13 -0000 1.1 @@ -0,0 +1,60 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption.impl; + +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.encryption.AgreementMethod; +import org.opensaml.xml.encryption.KANonce; +import org.opensaml.xml.encryption.OriginatorKeyInfo; +import org.opensaml.xml.encryption.RecipientKeyInfo; +import org.opensaml.xml.io.UnmarshallingException; +import org.w3c.dom.Attr; + +/** + * A thread-safe Unmarshaller for {@link org.opensaml.xml.encryption.AgreementMethod} objects. + */ +public class AgreementMethodUnmarshaller extends AbstractXMLEncryptionUnmarshaller { + + /** {@inheritDoc} */ + protected void processAttribute(XMLObject xmlObject, Attr attribute) throws UnmarshallingException { + AgreementMethod am = (AgreementMethod) xmlObject; + + if (attribute.getLocalName().equals(AgreementMethod.ALGORITHM_ATTRIBUTE_NAME)) { + am.setAlgorithm(attribute.getValue()); + } else { + super.processAttribute(xmlObject, attribute); + } + } + + /** {@inheritDoc} */ + protected void processChildElement(XMLObject parentXMLObject, XMLObject childXMLObject) + throws UnmarshallingException { + AgreementMethod am = (AgreementMethod) parentXMLObject; + + if (childXMLObject instanceof KANonce) { + am.setKANonce((KANonce) childXMLObject); + } else if (childXMLObject instanceof OriginatorKeyInfo) { + am.setOriginatorKeyInfo((OriginatorKeyInfo) childXMLObject); + } else if (childXMLObject instanceof RecipientKeyInfo) { + am.setRecipientKeyInfo((RecipientKeyInfo) childXMLObject); + } else { + am.getUnknownXMLObjects().add(childXMLObject); + } + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/CarriedKeyNameBuilder.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/CarriedKeyNameBuilder.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/CarriedKeyNameBuilder.java 17 Aug 2012 15:17:10 -0000 1.1 @@ -0,0 +1,46 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption.impl; + +import org.opensaml.xml.AbstractXMLObjectBuilder; +import org.opensaml.xml.encryption.CarriedKeyName; +import org.opensaml.xml.encryption.XMLEncryptionBuilder; +import org.opensaml.xml.util.XMLConstants; + +/** + * Builder of {@link org.opensaml.xml.encryption.CarriedKeyName}. + */ +public class CarriedKeyNameBuilder extends AbstractXMLObjectBuilder implements + XMLEncryptionBuilder { + + /** Constructor. */ + public CarriedKeyNameBuilder() { + } + + /** {@inheritDoc} */ + public CarriedKeyName buildObject(String namespaceURI, String localName, String namespacePrefix) { + return new CarriedKeyNameImpl(namespaceURI, localName, namespacePrefix); + } + + /** {@inheritDoc} */ + public CarriedKeyName buildObject() { + return buildObject(XMLConstants.XMLENC_NS, CarriedKeyName.DEFAULT_ELEMENT_LOCAL_NAME, + XMLConstants.XMLENC_PREFIX); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/CarriedKeyNameImpl.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/CarriedKeyNameImpl.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/CarriedKeyNameImpl.java 17 Aug 2012 15:17:12 -0000 1.1 @@ -0,0 +1,39 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption.impl; + +import org.opensaml.xml.encryption.CarriedKeyName; +import org.opensaml.xml.schema.impl.XSStringImpl; + +/** + * Concrete implementation of {@link org.opensaml.xml.encryption.CarriedKeyName}. + */ +public class CarriedKeyNameImpl extends XSStringImpl implements CarriedKeyName { + + /** + * Constructor. + * + * @param namespaceURI namespace URI + * @param elementLocalName local name + * @param namespacePrefix namespace prefix + */ + protected CarriedKeyNameImpl(String namespaceURI, String elementLocalName, String namespacePrefix) { + super(namespaceURI, elementLocalName, namespacePrefix); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/CipherDataBuilder.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/CipherDataBuilder.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/CipherDataBuilder.java 17 Aug 2012 15:17:12 -0000 1.1 @@ -0,0 +1,45 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption.impl; + +import org.opensaml.xml.AbstractXMLObjectBuilder; +import org.opensaml.xml.encryption.CipherData; +import org.opensaml.xml.encryption.XMLEncryptionBuilder; +import org.opensaml.xml.util.XMLConstants; + +/** + * Builder of {@link org.opensaml.xml.encryption.CipherData}. + */ +public class CipherDataBuilder extends AbstractXMLObjectBuilder implements + XMLEncryptionBuilder { + + /** Constructor. */ + public CipherDataBuilder() { + } + + /** {@inheritDoc} */ + public CipherData buildObject(String namespaceURI, String localName, String namespacePrefix) { + return new CipherDataImpl(namespaceURI, localName, namespacePrefix); + } + + /** {@inheritDoc} */ + public CipherData buildObject() { + return buildObject(XMLConstants.XMLENC_NS, CipherData.DEFAULT_ELEMENT_LOCAL_NAME, XMLConstants.XMLENC_PREFIX); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/CipherDataImpl.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/CipherDataImpl.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/CipherDataImpl.java 17 Aug 2012 15:17:13 -0000 1.1 @@ -0,0 +1,90 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption.impl; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.encryption.CipherData; +import org.opensaml.xml.encryption.CipherReference; +import org.opensaml.xml.encryption.CipherValue; +import org.opensaml.xml.validation.AbstractValidatingXMLObject; + +/** + * Concrete implementation of {@link org.opensaml.xml.encryption.CipherData}. + */ +public class CipherDataImpl extends AbstractValidatingXMLObject implements CipherData { + + /** CipherValue child element. */ + private CipherValue cipherValue; + + /** CipherReference child element. */ + private CipherReference cipherReference; + + /** + * Constructor. + * + * @param namespaceURI namespace URI + * @param elementLocalName local name + * @param namespacePrefix namespace prefix + */ + protected CipherDataImpl(String namespaceURI, String elementLocalName, String namespacePrefix) { + super(namespaceURI, elementLocalName, namespacePrefix); + } + + /** {@inheritDoc} */ + public CipherValue getCipherValue() { + return this.cipherValue; + } + + /** {@inheritDoc} */ + public void setCipherValue(CipherValue newCipherValue) { + this.cipherValue = prepareForAssignment(this.cipherValue, newCipherValue); + } + + /** {@inheritDoc} */ + public CipherReference getCipherReference() { + return this.cipherReference; + } + + /** {@inheritDoc} */ + public void setCipherReference(CipherReference newCipherReference) { + this.cipherReference = prepareForAssignment(this.cipherReference, newCipherReference); + } + + /** {@inheritDoc} */ + public List getOrderedChildren() { + ArrayList children = new ArrayList(); + + if (cipherValue != null) { + children.add(cipherValue); + } + if (cipherReference != null) { + children.add(cipherReference); + } + + if (children.size() == 0) { + return null; + } + + return Collections.unmodifiableList(children); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/CipherDataMarshaller.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/CipherDataMarshaller.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/CipherDataMarshaller.java 17 Aug 2012 15:17:11 -0000 1.1 @@ -0,0 +1,25 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption.impl; + +/** + * A thread-safe Marshaller for {@link org.opensaml.xml.encryption.CipherData} objects. + */ +public class CipherDataMarshaller extends AbstractXMLEncryptionMarshaller { + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/CipherDataUnmarshaller.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/CipherDataUnmarshaller.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/CipherDataUnmarshaller.java 17 Aug 2012 15:17:13 -0000 1.1 @@ -0,0 +1,45 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption.impl; + +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.encryption.CipherData; +import org.opensaml.xml.encryption.CipherReference; +import org.opensaml.xml.encryption.CipherValue; +import org.opensaml.xml.io.UnmarshallingException; + +/** + * A thread-safe Unmarshaller for {@link org.opensaml.xml.encryption.CipherData} objects. + */ +public class CipherDataUnmarshaller extends AbstractXMLEncryptionUnmarshaller { + + /** {@inheritDoc} */ + protected void processChildElement(XMLObject parentXMLObject, XMLObject childXMLObject) + throws UnmarshallingException { + CipherData cipherData = (CipherData) parentXMLObject; + + if (childXMLObject instanceof CipherValue) { + cipherData.setCipherValue((CipherValue) childXMLObject); + } else if (childXMLObject instanceof CipherReference) { + cipherData.setCipherReference((CipherReference) childXMLObject); + } else { + super.processChildElement(parentXMLObject, childXMLObject); + } + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/CipherReferenceBuilder.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/CipherReferenceBuilder.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/CipherReferenceBuilder.java 17 Aug 2012 15:17:13 -0000 1.1 @@ -0,0 +1,46 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption.impl; + +import org.opensaml.xml.AbstractXMLObjectBuilder; +import org.opensaml.xml.encryption.CipherReference; +import org.opensaml.xml.encryption.XMLEncryptionBuilder; +import org.opensaml.xml.util.XMLConstants; + +/** + * Builder of {@link org.opensaml.xml.encryption.CipherReference}. + */ +public class CipherReferenceBuilder extends AbstractXMLObjectBuilder implements + XMLEncryptionBuilder { + + /** Constructor. */ + public CipherReferenceBuilder() { + } + + /** {@inheritDoc} */ + public CipherReference buildObject(String namespaceURI, String localName, String namespacePrefix) { + return new CipherReferenceImpl(namespaceURI, localName, namespacePrefix); + } + + /** {@inheritDoc} */ + public CipherReference buildObject() { + return buildObject(XMLConstants.XMLENC_NS, CipherReference.DEFAULT_ELEMENT_LOCAL_NAME, + XMLConstants.XMLENC_PREFIX); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/CipherReferenceImpl.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/CipherReferenceImpl.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/CipherReferenceImpl.java 17 Aug 2012 15:17:13 -0000 1.1 @@ -0,0 +1,86 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption.impl; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.encryption.CipherReference; +import org.opensaml.xml.encryption.Transforms; +import org.opensaml.xml.validation.AbstractValidatingXMLObject; + +/** + * Concrete implementation of {@link org.opensaml.xml.encryption.CipherReference}. + */ +public class CipherReferenceImpl extends AbstractValidatingXMLObject implements CipherReference { + + /** URI attribute value. */ + private String uri; + + /** Transforms child element value. */ + private Transforms transforms; + + /** + * Constructor. + * + * @param namespaceURI namespace URI + * @param elementLocalName local name + * @param namespacePrefix namespace prefix + */ + protected CipherReferenceImpl(String namespaceURI, String elementLocalName, String namespacePrefix) { + super(namespaceURI, elementLocalName, namespacePrefix); + } + + /** {@inheritDoc} */ + public String getURI() { + return this.uri; + } + + /** {@inheritDoc} */ + public void setURI(String newURI) { + this.uri = prepareForAssignment(this.uri, newURI); + } + + /** {@inheritDoc} */ + public Transforms getTransforms() { + return this.transforms; + } + + /** {@inheritDoc} */ + public void setTransforms(Transforms newTransforms) { + this.transforms = prepareForAssignment(this.transforms, newTransforms); + } + + /** {@inheritDoc} */ + public List getOrderedChildren() { + ArrayList children = new ArrayList(); + + if (transforms != null) { + children.add(transforms); + } + + if (children.size() == 0) { + return null; + } + + return Collections.unmodifiableList(children); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/CipherReferenceMarshaller.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/CipherReferenceMarshaller.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/CipherReferenceMarshaller.java 17 Aug 2012 15:17:10 -0000 1.1 @@ -0,0 +1,41 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption.impl; + +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.encryption.CipherReference; +import org.opensaml.xml.io.MarshallingException; +import org.w3c.dom.Element; + +/** + * A thread-safe Marshaller for {@link org.opensaml.xml.encryption.CipherReference} objects. + */ +public class CipherReferenceMarshaller extends AbstractXMLEncryptionMarshaller { + + /** {@inheritDoc} */ + protected void marshallAttributes(XMLObject xmlObject, Element domElement) throws MarshallingException { + CipherReference cr = (CipherReference) xmlObject; + + if (cr.getURI() != null) { + domElement.setAttributeNS(null, CipherReference.URI_ATTRIB_NAME, cr.getURI()); + } else { + super.marshallAttributes(xmlObject, domElement); + } + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/CipherReferenceUnmarshaller.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/CipherReferenceUnmarshaller.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/CipherReferenceUnmarshaller.java 17 Aug 2012 15:17:12 -0000 1.1 @@ -0,0 +1,54 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption.impl; + +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.encryption.CipherReference; +import org.opensaml.xml.encryption.Transforms; +import org.opensaml.xml.io.UnmarshallingException; +import org.w3c.dom.Attr; + +/** + * A thread-safe Unmarshaller for {@link org.opensaml.xml.encryption.CipherReference} objects. + */ +public class CipherReferenceUnmarshaller extends AbstractXMLEncryptionUnmarshaller { + + /** {@inheritDoc} */ + protected void processAttribute(XMLObject xmlObject, Attr attribute) throws UnmarshallingException { + CipherReference cr = (CipherReference) xmlObject; + + if (attribute.getLocalName().equals(CipherReference.URI_ATTRIB_NAME)) { + cr.setURI(attribute.getValue()); + } else { + super.processAttribute(xmlObject, attribute); + } + } + + /** {@inheritDoc} */ + protected void processChildElement(XMLObject parentXMLObject, XMLObject childXMLObject) + throws UnmarshallingException { + CipherReference cr = (CipherReference) parentXMLObject; + + if (childXMLObject instanceof Transforms) { + cr.setTransforms((Transforms) childXMLObject); + } else { + super.processChildElement(parentXMLObject, childXMLObject); + } + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/CipherValueBuilder.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/CipherValueBuilder.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/CipherValueBuilder.java 17 Aug 2012 15:17:13 -0000 1.1 @@ -0,0 +1,45 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption.impl; + +import org.opensaml.xml.AbstractXMLObjectBuilder; +import org.opensaml.xml.encryption.CipherValue; +import org.opensaml.xml.encryption.XMLEncryptionBuilder; +import org.opensaml.xml.util.XMLConstants; + +/** + * Builder of {@link org.opensaml.xml.encryption.CipherValue}. + */ +public class CipherValueBuilder extends AbstractXMLObjectBuilder implements + XMLEncryptionBuilder { + + /** Constructor. */ + public CipherValueBuilder() { + } + + /** {@inheritDoc} */ + public CipherValue buildObject(String namespaceURI, String localName, String namespacePrefix) { + return new CipherValueImpl(namespaceURI, localName, namespacePrefix); + } + + /** {@inheritDoc} */ + public CipherValue buildObject() { + return buildObject(XMLConstants.XMLENC_NS, CipherValue.DEFAULT_ELEMENT_LOCAL_NAME, XMLConstants.XMLENC_PREFIX); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/CipherValueImpl.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/CipherValueImpl.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/CipherValueImpl.java 17 Aug 2012 15:17:12 -0000 1.1 @@ -0,0 +1,39 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption.impl; + +import org.opensaml.xml.encryption.CipherValue; +import org.opensaml.xml.schema.impl.XSBase64BinaryImpl; + +/** + * Concrete implementation of {@link org.opensaml.xml.encryption.CipherValue}. + */ +public class CipherValueImpl extends XSBase64BinaryImpl implements CipherValue { + + /** + * Constructor. + * + * @param namespaceURI namespace URI + * @param elementLocalName local name + * @param namespacePrefix namespace prefix + */ + protected CipherValueImpl(String namespaceURI, String elementLocalName, String namespacePrefix) { + super(namespaceURI, elementLocalName, namespacePrefix); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/DHKeyValueBuilder.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/DHKeyValueBuilder.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/DHKeyValueBuilder.java 17 Aug 2012 15:17:11 -0000 1.1 @@ -0,0 +1,45 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption.impl; + +import org.opensaml.xml.AbstractXMLObjectBuilder; +import org.opensaml.xml.encryption.DHKeyValue; +import org.opensaml.xml.encryption.XMLEncryptionBuilder; +import org.opensaml.xml.util.XMLConstants; + +/** + * Builder of {@link org.opensaml.xml.encryption.DHKeyValue}. + */ +public class DHKeyValueBuilder extends AbstractXMLObjectBuilder implements + XMLEncryptionBuilder { + + /** Constructor. */ + public DHKeyValueBuilder() { + } + + /** {@inheritDoc} */ + public DHKeyValue buildObject(String namespaceURI, String localName, String namespacePrefix) { + return new DHKeyValueImpl(namespaceURI, localName, namespacePrefix); + } + + /** {@inheritDoc} */ + public DHKeyValue buildObject() { + return buildObject(XMLConstants.XMLENC_NS, DHKeyValue.DEFAULT_ELEMENT_LOCAL_NAME, XMLConstants.XMLENC_PREFIX); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/DHKeyValueImpl.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/DHKeyValueImpl.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/DHKeyValueImpl.java 17 Aug 2012 15:17:11 -0000 1.1 @@ -0,0 +1,158 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption.impl; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.encryption.DHKeyValue; +import org.opensaml.xml.encryption.Generator; +import org.opensaml.xml.encryption.P; +import org.opensaml.xml.encryption.PgenCounter; +import org.opensaml.xml.encryption.Public; +import org.opensaml.xml.encryption.Q; +import org.opensaml.xml.encryption.Seed; +import org.opensaml.xml.validation.AbstractValidatingXMLObject; + +/** + * Concrete implementation of {@link org.opensaml.xml.encryption.DHKeyValue}. + */ +public class DHKeyValueImpl extends AbstractValidatingXMLObject implements DHKeyValue { + + /** P child element. */ + private P p; + + /** Q child element. */ + private Q q; + + /** Generator child element. */ + private Generator generator; + + /** Public element. */ + private Public publicChild; + + /** seed child element. */ + private Seed seed; + + /** pgenCounter child element. */ + private PgenCounter pgenCounter; + + /** + * Constructor. + * + * @param namespaceURI namespace URI + * @param elementLocalName local name + * @param namespacePrefix namespace prefix + */ + protected DHKeyValueImpl(String namespaceURI, String elementLocalName, String namespacePrefix) { + super(namespaceURI, elementLocalName, namespacePrefix); + } + + /** {@inheritDoc} */ + public P getP() { + return this.p; + } + + /** {@inheritDoc} */ + public void setP(P newP) { + this.p = prepareForAssignment(this.p, newP); + } + + /** {@inheritDoc} */ + public Q getQ() { + return this.q; + } + + /** {@inheritDoc} */ + public void setQ(Q newQ) { + this.q = prepareForAssignment(this.q, newQ); + } + + /** {@inheritDoc} */ + public Generator getGenerator() { + return this.generator; + } + + /** {@inheritDoc} */ + public void setGenerator(Generator newGenerator) { + this.generator = prepareForAssignment(this.generator, newGenerator); + } + + /** {@inheritDoc} */ + public Public getPublic() { + return this.publicChild; + } + + /** {@inheritDoc} */ + public void setPublic(Public newPublic) { + this.publicChild = prepareForAssignment(this.publicChild, newPublic); + } + + /** {@inheritDoc} */ + public Seed getSeed() { + return this.seed; + } + + /** {@inheritDoc} */ + public void setSeed(Seed newSeed) { + this.seed = prepareForAssignment(this.seed, newSeed); + } + + /** {@inheritDoc} */ + public PgenCounter getPgenCounter() { + return this.pgenCounter; + } + + /** {@inheritDoc} */ + public void setPgenCounter(PgenCounter newPgenCounter) { + this.pgenCounter = prepareForAssignment(this.pgenCounter, newPgenCounter); + } + + /** {@inheritDoc} */ + public List getOrderedChildren() { + ArrayList children = new ArrayList(); + + if (p != null) { + children.add(p); + } + if (q!= null) { + children.add(q); + } + if (generator != null) { + children.add(generator); + } + if (publicChild != null) { + children.add(publicChild); + } + if (seed != null) { + children.add(seed); + } + if (pgenCounter != null) { + children.add(pgenCounter); + } + + if (children.size() == 0) { + return null; + } + + return Collections.unmodifiableList(children); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/DHKeyValueMarshaller.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/DHKeyValueMarshaller.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/DHKeyValueMarshaller.java 17 Aug 2012 15:17:10 -0000 1.1 @@ -0,0 +1,25 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption.impl; + +/** + * A thread-safe Marshaller for {@link org.opensaml.xml.encryption.DHKeyValue} objects. + */ +public class DHKeyValueMarshaller extends AbstractXMLEncryptionMarshaller { + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/DHKeyValueUnmarshaller.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/DHKeyValueUnmarshaller.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/DHKeyValueUnmarshaller.java 17 Aug 2012 15:17:10 -0000 1.1 @@ -0,0 +1,57 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption.impl; + +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.encryption.DHKeyValue; +import org.opensaml.xml.encryption.Generator; +import org.opensaml.xml.encryption.P; +import org.opensaml.xml.encryption.PgenCounter; +import org.opensaml.xml.encryption.Public; +import org.opensaml.xml.encryption.Q; +import org.opensaml.xml.encryption.Seed; +import org.opensaml.xml.io.UnmarshallingException; + +/** + * A thread-safe Unmarshaller for {@link org.opensaml.xml.encryption.DHKeyValue} objects. + */ +public class DHKeyValueUnmarshaller extends AbstractXMLEncryptionUnmarshaller { + + /** {@inheritDoc} */ + protected void processChildElement(XMLObject parentXMLObject, XMLObject childXMLObject) + throws UnmarshallingException { + DHKeyValue keyValue = (DHKeyValue) parentXMLObject; + + if (childXMLObject instanceof P) { + keyValue.setP((P) childXMLObject); + } else if (childXMLObject instanceof Q) { + keyValue.setQ((Q) childXMLObject); + } else if (childXMLObject instanceof Generator) { + keyValue.setGenerator((Generator) childXMLObject); + } else if (childXMLObject instanceof Public) { + keyValue.setPublic((Public) childXMLObject); + } else if (childXMLObject instanceof Seed) { + keyValue.setSeed((Seed) childXMLObject); + } else if (childXMLObject instanceof PgenCounter) { + keyValue.setPgenCounter((PgenCounter) childXMLObject); + } else { + super.processChildElement(parentXMLObject, childXMLObject); + } + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/DataReferenceBuilder.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/DataReferenceBuilder.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/DataReferenceBuilder.java 17 Aug 2012 15:17:10 -0000 1.1 @@ -0,0 +1,46 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption.impl; + +import org.opensaml.xml.AbstractXMLObjectBuilder; +import org.opensaml.xml.encryption.DataReference; +import org.opensaml.xml.encryption.XMLEncryptionBuilder; +import org.opensaml.xml.util.XMLConstants; + +/** + * Builder of {@link org.opensaml.xml.encryption.DataReference}. + */ +public class DataReferenceBuilder extends AbstractXMLObjectBuilder implements + XMLEncryptionBuilder { + + /** Constructor. */ + public DataReferenceBuilder() { + } + + /** {@inheritDoc} */ + public DataReference buildObject(String namespaceURI, String localName, String namespacePrefix) { + return new DataReferenceImpl(namespaceURI, localName, namespacePrefix); + } + + /** {@inheritDoc} */ + public DataReference buildObject() { + return buildObject(XMLConstants.XMLENC_NS, DataReference.DEFAULT_ELEMENT_LOCAL_NAME, + XMLConstants.XMLENC_PREFIX); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/DataReferenceImpl.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/DataReferenceImpl.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/DataReferenceImpl.java 17 Aug 2012 15:17:13 -0000 1.1 @@ -0,0 +1,38 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption.impl; + +import org.opensaml.xml.encryption.DataReference; + +/** + * Concrete implementation of {@link org.opensaml.xml.encryption.DataReference}. + */ +public class DataReferenceImpl extends ReferenceTypeImpl implements DataReference { + + /** + * Constructor. + * + * @param namespaceURI namespace URI + * @param elementLocalName local name + * @param namespacePrefix namespace prefix + */ + protected DataReferenceImpl(String namespaceURI, String elementLocalName, String namespacePrefix) { + super(namespaceURI, elementLocalName, namespacePrefix); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/DataReferenceMarshaller.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/DataReferenceMarshaller.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/DataReferenceMarshaller.java 17 Aug 2012 15:17:12 -0000 1.1 @@ -0,0 +1,25 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption.impl; + +/** + * A thread-safe Marshaller for {@link org.opensaml.xml.encryption.DataReference} objects. + */ +public class DataReferenceMarshaller extends ReferenceTypeMarshaller { + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/DataReferenceUnmarshaller.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/DataReferenceUnmarshaller.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/DataReferenceUnmarshaller.java 17 Aug 2012 15:17:13 -0000 1.1 @@ -0,0 +1,25 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption.impl; + +/** + * A thread-safe Unmarshaller for {@link org.opensaml.xml.encryption.DataReference} objects. + */ +public class DataReferenceUnmarshaller extends ReferenceTypeUnmarshaller { + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/EncryptedDataBuilder.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/EncryptedDataBuilder.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/EncryptedDataBuilder.java 17 Aug 2012 15:17:11 -0000 1.1 @@ -0,0 +1,46 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption.impl; + +import org.opensaml.xml.AbstractXMLObjectBuilder; +import org.opensaml.xml.encryption.EncryptedData; +import org.opensaml.xml.encryption.XMLEncryptionBuilder; +import org.opensaml.xml.util.XMLConstants; + +/** + * Builder of {@link org.opensaml.xml.encryption.EncryptedData}. + */ +public class EncryptedDataBuilder extends AbstractXMLObjectBuilder implements + XMLEncryptionBuilder { + + /** Constructor. */ + public EncryptedDataBuilder() { + } + + /** {@inheritDoc} */ + public EncryptedData buildObject() { + return buildObject(XMLConstants.XMLENC_NS, EncryptedData.DEFAULT_ELEMENT_LOCAL_NAME, + XMLConstants.XMLENC_PREFIX); + } + + /** {@inheritDoc} */ + public EncryptedData buildObject(String namespaceURI, String localName, String namespacePrefix) { + return new EncryptedDataImpl(namespaceURI, localName, namespacePrefix); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/EncryptedDataImpl.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/EncryptedDataImpl.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/EncryptedDataImpl.java 17 Aug 2012 15:17:11 -0000 1.1 @@ -0,0 +1,38 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption.impl; + +import org.opensaml.xml.encryption.EncryptedData; + +/** + * Concrete implementation of {@link org.opensaml.xml.encryption.EncryptedData}. + */ +public class EncryptedDataImpl extends EncryptedTypeImpl implements EncryptedData { + + /** + * Constructor. + * + * @param namespaceURI namespace URI + * @param elementLocalName local name + * @param namespacePrefix namespace prefix + */ + protected EncryptedDataImpl(String namespaceURI, String elementLocalName, String namespacePrefix) { + super(namespaceURI, elementLocalName, namespacePrefix); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/EncryptedDataMarshaller.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/EncryptedDataMarshaller.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/EncryptedDataMarshaller.java 17 Aug 2012 15:17:12 -0000 1.1 @@ -0,0 +1,25 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption.impl; + +/** + * A thread-safe Marshaller for {@link org.opensaml.xml.encryption.EncryptedData} objects. + */ +public class EncryptedDataMarshaller extends EncryptedTypeMarshaller { + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/EncryptedDataUnmarshaller.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/EncryptedDataUnmarshaller.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/EncryptedDataUnmarshaller.java 17 Aug 2012 15:17:11 -0000 1.1 @@ -0,0 +1,25 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption.impl; + +/** + * A thread-safe Unmarshaller for {@link org.opensaml.xml.encryption.EncryptedData} objects. + */ +public class EncryptedDataUnmarshaller extends EncryptedTypeUnmarshaller { + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/EncryptedKeyBuilder.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/EncryptedKeyBuilder.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/EncryptedKeyBuilder.java 17 Aug 2012 15:17:11 -0000 1.1 @@ -0,0 +1,45 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption.impl; + +import org.opensaml.xml.AbstractXMLObjectBuilder; +import org.opensaml.xml.encryption.EncryptedKey; +import org.opensaml.xml.encryption.XMLEncryptionBuilder; +import org.opensaml.xml.util.XMLConstants; + +/** + * Builder of {@link org.opensaml.xml.encryption.EncryptedKey}. + */ +public class EncryptedKeyBuilder extends AbstractXMLObjectBuilder + implements XMLEncryptionBuilder { + + /** Constructor. */ + public EncryptedKeyBuilder() { + } + + /** {@inheritDoc} */ + public EncryptedKey buildObject() { + return buildObject(XMLConstants.XMLENC_NS, EncryptedKey.DEFAULT_ELEMENT_LOCAL_NAME, XMLConstants.XMLENC_PREFIX); + } + + /** {@inheritDoc} */ + public EncryptedKey buildObject(String namespaceURI, String localName, String namespacePrefix) { + return new EncryptedKeyImpl(namespaceURI, localName, namespacePrefix); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/EncryptedKeyImpl.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/EncryptedKeyImpl.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/EncryptedKeyImpl.java 17 Aug 2012 15:17:12 -0000 1.1 @@ -0,0 +1,106 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption.impl; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.encryption.CarriedKeyName; +import org.opensaml.xml.encryption.EncryptedKey; +import org.opensaml.xml.encryption.ReferenceList; + +/** + * Concrete implementation of {@link org.opensaml.xml.encryption.EncryptedKey}. + */ +public class EncryptedKeyImpl extends EncryptedTypeImpl implements EncryptedKey { + + /** Recipient value. */ + private String recipient; + + /** CarriedKeyName value. */ + private CarriedKeyName carriedKeyName; + + /** ReferenceList value. */ + private ReferenceList referenceList; + + /** + * Constructor. + * + * @param namespaceURI namespace URI + * @param elementLocalName local name + * @param namespacePrefix namespace prefix + */ + protected EncryptedKeyImpl(String namespaceURI, String elementLocalName, String namespacePrefix) { + super(namespaceURI, elementLocalName, namespacePrefix); + } + + /** {@inheritDoc} */ + public String getRecipient() { + return this.recipient; + } + + /** {@inheritDoc} */ + public void setRecipient(String newRecipient) { + this.recipient = prepareForAssignment(this.recipient, newRecipient); + } + + /** {@inheritDoc} */ + public ReferenceList getReferenceList() { + return this.referenceList; + } + + /** {@inheritDoc} */ + public void setReferenceList(ReferenceList newReferenceList) { + this.referenceList = prepareForAssignment(this.referenceList, newReferenceList); + } + + /** {@inheritDoc} */ + public CarriedKeyName getCarriedKeyName() { + return this.carriedKeyName; + } + + /** {@inheritDoc} */ + public void setCarriedKeyName(CarriedKeyName newCarriedKeyName) { + this.carriedKeyName = prepareForAssignment(this.carriedKeyName, newCarriedKeyName); + } + + /** {@inheritDoc} */ + public List getOrderedChildren() { + ArrayList children = new ArrayList(); + + if (super.getOrderedChildren() != null) { + children.addAll(super.getOrderedChildren()); + } + + if (referenceList != null) { + children.add(referenceList); + } + if (carriedKeyName != null) { + children.add(carriedKeyName); + } + + if (children.size() == 0) { + return null; + } + + return Collections.unmodifiableList(children); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/EncryptedKeyMarshaller.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/EncryptedKeyMarshaller.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/EncryptedKeyMarshaller.java 17 Aug 2012 15:17:10 -0000 1.1 @@ -0,0 +1,41 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption.impl; + +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.encryption.EncryptedKey; +import org.opensaml.xml.io.MarshallingException; +import org.w3c.dom.Element; + +/** + * A thread-safe Marshaller for {@link org.opensaml.xml.encryption.EncryptedKey} objects. + */ +public class EncryptedKeyMarshaller extends EncryptedTypeMarshaller { + + /** {@inheritDoc} */ + protected void marshallAttributes(XMLObject xmlObject, Element domElement) throws MarshallingException { + EncryptedKey ek = (EncryptedKey) xmlObject; + + if (ek.getRecipient() != null) { + domElement.setAttributeNS(null, EncryptedKey.RECIPIENT_ATTRIB_NAME, ek.getRecipient()); + } + + super.marshallAttributes(xmlObject, domElement); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/EncryptedKeyUnmarshaller.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/EncryptedKeyUnmarshaller.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/EncryptedKeyUnmarshaller.java 17 Aug 2012 15:17:11 -0000 1.1 @@ -0,0 +1,57 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption.impl; + +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.encryption.CarriedKeyName; +import org.opensaml.xml.encryption.EncryptedKey; +import org.opensaml.xml.encryption.ReferenceList; +import org.opensaml.xml.io.UnmarshallingException; +import org.w3c.dom.Attr; + +/** + * A thread-safe Unmarshaller for {@link org.opensaml.xml.encryption.EncryptedKey} objects. + */ +public class EncryptedKeyUnmarshaller extends EncryptedTypeUnmarshaller { + + /** {@inheritDoc} */ + protected void processAttribute(XMLObject xmlObject, Attr attribute) throws UnmarshallingException { + EncryptedKey ek = (EncryptedKey) xmlObject; + + if (attribute.getLocalName().equals(EncryptedKey.RECIPIENT_ATTRIB_NAME)) { + ek.setRecipient(attribute.getValue()); + } else { + super.processAttribute(xmlObject, attribute); + } + } + + /** {@inheritDoc} */ + protected void processChildElement(XMLObject parentXMLObject, XMLObject childXMLObject) + throws UnmarshallingException { + EncryptedKey ek = (EncryptedKey) parentXMLObject; + + if (childXMLObject instanceof ReferenceList) { + ek.setReferenceList((ReferenceList) childXMLObject); + } else if (childXMLObject instanceof CarriedKeyName) { + ek.setCarriedKeyName((CarriedKeyName) childXMLObject); + } else { + super.processChildElement(parentXMLObject, childXMLObject); + } + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/EncryptedTypeImpl.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/EncryptedTypeImpl.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/EncryptedTypeImpl.java 17 Aug 2012 15:17:11 -0000 1.1 @@ -0,0 +1,178 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption.impl; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.encryption.CipherData; +import org.opensaml.xml.encryption.EncryptedType; +import org.opensaml.xml.encryption.EncryptionMethod; +import org.opensaml.xml.encryption.EncryptionProperties; +import org.opensaml.xml.signature.KeyInfo; +import org.opensaml.xml.validation.AbstractValidatingXMLObject; + +/** + * Abstract implementation of {@link org.opensaml.xml.encryption.EncryptedType}. + */ +public abstract class EncryptedTypeImpl extends AbstractValidatingXMLObject implements EncryptedType { + + /** id attribute value. */ + private String id; + + /** Type attribute value. */ + private String type; + + /** MimeType attribute value. */ + private String mimeType; + + /** Encoding attribute value. */ + private String encoding; + + /** EncryptionMethod child element. */ + private EncryptionMethod encryptionMethod; + + /** EncryptionMethod child element. */ + private KeyInfo keyInfo; + + /** CipherData child element. */ + private CipherData cipherData; + + /** EncryptionProperties child element. */ + private EncryptionProperties encryptionProperties; + + /** + * Constructor + * + * @param namespaceURI + * @param elementLocalName + * @param namespacePrefix + */ + protected EncryptedTypeImpl(String namespaceURI, String elementLocalName, String namespacePrefix) { + super(namespaceURI, elementLocalName, namespacePrefix); + } + + /** {@inheritDoc} */ + public String getID() { + return this.id; + } + + /** {@inheritDoc} */ + public void setID(String newID) { + String oldID = this.id; + this.id = prepareForAssignment(this.id, newID); + registerOwnID(oldID, this.id); + } + + /** {@inheritDoc} */ + public String getType() { + return this.type; + } + + /** {@inheritDoc} */ + public void setType(String newType) { + this.type = prepareForAssignment(this.type, newType); + } + + /** {@inheritDoc} */ + public String getMimeType() { + return this.mimeType; + } + + /** {@inheritDoc} */ + public void setMimeType(String newMimeType) { + this.mimeType = prepareForAssignment(this.mimeType, newMimeType); + } + + /** {@inheritDoc} */ + public String getEncoding() { + return this.encoding; + } + + /** {@inheritDoc} */ + public void setEncoding(String newEncoding) { + this.encoding = prepareForAssignment(this.encoding, newEncoding); + } + + /** {@inheritDoc} */ + public EncryptionMethod getEncryptionMethod() { + return this.encryptionMethod; + } + + /** {@inheritDoc} */ + public void setEncryptionMethod(EncryptionMethod newEncryptionMethod) { + this.encryptionMethod = prepareForAssignment(this.encryptionMethod, newEncryptionMethod); + } + + /** {@inheritDoc} */ + public KeyInfo getKeyInfo() { + return this.keyInfo; + } + + /** {@inheritDoc} */ + public void setKeyInfo(KeyInfo newKeyInfo) { + this.keyInfo = prepareForAssignment(this.keyInfo, newKeyInfo); + } + + /** {@inheritDoc} */ + public CipherData getCipherData() { + return this.cipherData; + } + + /** {@inheritDoc} */ + public void setCipherData(CipherData newCipherData) { + this.cipherData = prepareForAssignment(this.cipherData, newCipherData); + } + + /** {@inheritDoc} */ + public EncryptionProperties getEncryptionProperties() { + return this.encryptionProperties; + } + + /** {@inheritDoc} */ + public void setEncryptionProperties(EncryptionProperties newEncryptionProperties) { + this.encryptionProperties = prepareForAssignment(this.encryptionProperties, newEncryptionProperties); + } + + /** {@inheritDoc} */ + public List getOrderedChildren() { + ArrayList children = new ArrayList(); + + if (encryptionMethod != null) { + children.add(encryptionMethod); + } + if (keyInfo != null) { + children.add(keyInfo); + } + if (cipherData != null) { + children.add(cipherData); + } + if (encryptionProperties!= null) { + children.add(encryptionProperties); + } + + if (children.size() == 0) { + return null; + } + + return Collections.unmodifiableList(children); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/EncryptedTypeMarshaller.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/EncryptedTypeMarshaller.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/EncryptedTypeMarshaller.java 17 Aug 2012 15:17:13 -0000 1.1 @@ -0,0 +1,53 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption.impl; + +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.encryption.EncryptedType; +import org.opensaml.xml.io.MarshallingException; +import org.w3c.dom.Element; + +/** + * A thread-safe Marshaller for {@link org.opensaml.xml.encryption.EncryptedType} objects. + */ +public abstract class EncryptedTypeMarshaller extends AbstractXMLEncryptionMarshaller { + + /** {@inheritDoc} */ + protected void marshallAttributes(XMLObject xmlObject, Element domElement) throws MarshallingException { + EncryptedType et = (EncryptedType) xmlObject; + + if (et.getID() != null) { + domElement.setAttributeNS(null, EncryptedType.ID_ATTRIB_NAME, et.getID()); + domElement.setIdAttributeNS(null, EncryptedType.ID_ATTRIB_NAME, true); + } + + if (et.getType() != null) { + domElement.setAttributeNS(null, EncryptedType.TYPE_ATTRIB_NAME, et.getType()); + } + + if (et.getMimeType() != null) { + domElement.setAttributeNS(null, EncryptedType.MIMETYPE_ATTRIB_NAME, et.getMimeType()); + } + + if (et.getEncoding() != null) { + domElement.setAttributeNS(null, EncryptedType.ENCODING_ATTRIB_NAME, et.getEncoding()); + } + + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/EncryptedTypeUnmarshaller.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/EncryptedTypeUnmarshaller.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/EncryptedTypeUnmarshaller.java 17 Aug 2012 15:17:11 -0000 1.1 @@ -0,0 +1,72 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption.impl; + +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.encryption.CipherData; +import org.opensaml.xml.encryption.EncryptedType; +import org.opensaml.xml.encryption.EncryptionMethod; +import org.opensaml.xml.encryption.EncryptionProperties; +import org.opensaml.xml.io.UnmarshallingException; +import org.opensaml.xml.signature.KeyInfo; +import org.w3c.dom.Attr; + +/** + * A thread-safe Unmarshaller for {@link org.opensaml.xml.encryption.EncryptedType} objects. + */ +public abstract class EncryptedTypeUnmarshaller extends AbstractXMLEncryptionUnmarshaller { + + /** {@inheritDoc} */ + protected void processChildElement(XMLObject parentXMLObject, XMLObject childXMLObject) + throws UnmarshallingException { + EncryptedType et = (EncryptedType) parentXMLObject; + + if (childXMLObject instanceof EncryptionMethod) { + et.setEncryptionMethod((EncryptionMethod) childXMLObject); + } else if (childXMLObject instanceof KeyInfo) { + et.setKeyInfo((KeyInfo) childXMLObject); + } else if (childXMLObject instanceof CipherData) { + et.setCipherData((CipherData) childXMLObject); + } else if (childXMLObject instanceof EncryptionProperties) { + et.setEncryptionProperties((EncryptionProperties) childXMLObject); + } else { + super.processChildElement(parentXMLObject, childXMLObject); + } + + } + + /** {@inheritDoc} */ + protected void processAttribute(XMLObject xmlObject, Attr attribute) throws UnmarshallingException { + EncryptedType et = (EncryptedType) xmlObject; + + if (attribute.getLocalName().equals(EncryptedType.ID_ATTRIB_NAME)) { + et.setID(attribute.getValue()); + attribute.getOwnerElement().setIdAttributeNode(attribute, true); + } else if (attribute.getLocalName().equals(EncryptedType.TYPE_ATTRIB_NAME)) { + et.setType(attribute.getValue()); + } else if (attribute.getLocalName().equals(EncryptedType.MIMETYPE_ATTRIB_NAME)) { + et.setMimeType(attribute.getValue()); + } else if (attribute.getLocalName().equals(EncryptedType.ENCODING_ATTRIB_NAME)) { + et.setEncoding(attribute.getValue()); + } else { + super.processAttribute(xmlObject, attribute); + } + + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/EncryptionMethodBuilder.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/EncryptionMethodBuilder.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/EncryptionMethodBuilder.java 17 Aug 2012 15:17:12 -0000 1.1 @@ -0,0 +1,47 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption.impl; + +import org.opensaml.xml.AbstractXMLObjectBuilder; +import org.opensaml.xml.encryption.EncryptionMethod; +import org.opensaml.xml.encryption.XMLEncryptionBuilder; +import org.opensaml.xml.util.XMLConstants; + +/** + * Builder of {@link org.opensaml.xml.encryption.EncryptionMethod} + */ +public class EncryptionMethodBuilder extends AbstractXMLObjectBuilder implements XMLEncryptionBuilder { + + /** + * Constructor. + * + */ + public EncryptionMethodBuilder() { + } + + /** {@inheritDoc} */ + public EncryptionMethod buildObject(String namespaceURI, String localName, String namespacePrefix) { + return new EncryptionMethodImpl(namespaceURI, localName, namespacePrefix); + } + + /** {@inheritDoc} */ + public EncryptionMethod buildObject() { + return buildObject(XMLConstants.XMLENC_NS, EncryptionMethod.DEFAULT_ELEMENT_LOCAL_NAME, XMLConstants.XMLENC_PREFIX); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/EncryptionMethodImpl.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/EncryptionMethodImpl.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/EncryptionMethodImpl.java 17 Aug 2012 15:17:13 -0000 1.1 @@ -0,0 +1,122 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption.impl; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import javax.xml.namespace.QName; + +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.encryption.EncryptionMethod; +import org.opensaml.xml.encryption.KeySize; +import org.opensaml.xml.encryption.OAEPparams; +import org.opensaml.xml.util.IndexedXMLObjectChildrenList; +import org.opensaml.xml.validation.AbstractValidatingXMLObject; + +/** + * Concrete implementation of {@link org.opensaml.xml.encryption.EncryptionMethod}. + */ +public class EncryptionMethodImpl extends AbstractValidatingXMLObject implements EncryptionMethod { + + /** Algorithm attribute value. */ + private String algorithm; + + /** KeySize child element value. */ + private KeySize keySize; + + /** OAEPparams child element value. */ + private OAEPparams oaepParams; + + /** "any" children. */ + private final IndexedXMLObjectChildrenList unknownChildren; + + /** + * Constructor. + * + * @param namespaceURI + * @param elementLocalName + * @param namespacePrefix + */ + protected EncryptionMethodImpl(String namespaceURI, String elementLocalName, String namespacePrefix) { + super(namespaceURI, elementLocalName, namespacePrefix); + + unknownChildren = new IndexedXMLObjectChildrenList(this); + } + + /** {@inheritDoc} */ + public String getAlgorithm() { + return this.algorithm; + } + + /** {@inheritDoc} */ + public void setAlgorithm(String newAlgorithm) { + this.algorithm = prepareForAssignment(this.algorithm, newAlgorithm); + } + + /** {@inheritDoc} */ + public KeySize getKeySize() { + return this.keySize; + } + + /** {@inheritDoc} */ + public void setKeySize(KeySize newKeySize) { + this.keySize = prepareForAssignment(this.keySize, newKeySize); + } + + /** {@inheritDoc} */ + public OAEPparams getOAEPparams() { + return this.oaepParams; + } + + /** {@inheritDoc} */ + public void setOAEPparams(OAEPparams newOAEPparams) { + this.oaepParams = prepareForAssignment(this.oaepParams, newOAEPparams); + } + + /** {@inheritDoc} */ + public List getUnknownXMLObjects() { + return this.unknownChildren; + } + /** {@inheritDoc} */ + public List getUnknownXMLObjects(QName typeOrName) { + return (List) unknownChildren.subList(typeOrName); + } + + /** {@inheritDoc} */ + public List getOrderedChildren() { + ArrayList children = new ArrayList(); + + if (keySize != null) { + children.add(keySize); + } + if (oaepParams != null) { + children.add(oaepParams); + } + + children.addAll(unknownChildren); + + if (children.size() == 0) { + return null; + } + + return Collections.unmodifiableList(children); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/EncryptionMethodMarshaller.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/EncryptionMethodMarshaller.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/EncryptionMethodMarshaller.java 17 Aug 2012 15:17:11 -0000 1.1 @@ -0,0 +1,39 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption.impl; + +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.encryption.EncryptionMethod; +import org.opensaml.xml.io.MarshallingException; +import org.w3c.dom.Element; + +/** + * A thread-safe Marshaller for {@link org.opensaml.xml.encryption.EncryptionMethod} objects. + */ +public class EncryptionMethodMarshaller extends AbstractXMLEncryptionMarshaller { + + /** {@inheritDoc} */ + protected void marshallAttributes(XMLObject xmlObject, Element domElement) throws MarshallingException { + EncryptionMethod em = (EncryptionMethod) xmlObject; + + if (em.getAlgorithm() != null) { + domElement.setAttributeNS(null, EncryptionMethod.ALGORITHM_ATTRIB_NAME, em.getAlgorithm()); + } + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/EncryptionMethodUnmarshaller.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/EncryptionMethodUnmarshaller.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/EncryptionMethodUnmarshaller.java 17 Aug 2012 15:17:13 -0000 1.1 @@ -0,0 +1,56 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption.impl; + +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.encryption.EncryptionMethod; +import org.opensaml.xml.encryption.KeySize; +import org.opensaml.xml.encryption.OAEPparams; +import org.opensaml.xml.io.UnmarshallingException; +import org.w3c.dom.Attr; + +/** + * A thread-safe Unmarshaller for {@link org.opensaml.xml.encryption.EncryptionMethod} objects. + */ +public class EncryptionMethodUnmarshaller extends AbstractXMLEncryptionUnmarshaller { + + /** {@inheritDoc} */ + protected void processAttribute(XMLObject xmlObject, Attr attribute) throws UnmarshallingException { + EncryptionMethod em = (EncryptionMethod) xmlObject; + + if (attribute.getLocalName().equals(EncryptionMethod.ALGORITHM_ATTRIB_NAME)) { + em.setAlgorithm(attribute.getValue()); + } else { + super.processAttribute(xmlObject, attribute); + } + } + + /** {@inheritDoc} */ + protected void processChildElement(XMLObject parentXMLObject, XMLObject childXMLObject) + throws UnmarshallingException { + EncryptionMethod em = (EncryptionMethod) parentXMLObject; + if (childXMLObject instanceof KeySize) { + em.setKeySize((KeySize) childXMLObject); + } else if (childXMLObject instanceof OAEPparams) { + em.setOAEPparams((OAEPparams) childXMLObject); + } else { + em.getUnknownXMLObjects().add(childXMLObject); + } + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/EncryptionPropertiesBuilder.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/EncryptionPropertiesBuilder.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/EncryptionPropertiesBuilder.java 17 Aug 2012 15:17:10 -0000 1.1 @@ -0,0 +1,48 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption.impl; + +import org.opensaml.xml.AbstractXMLObjectBuilder; +import org.opensaml.xml.encryption.EncryptionProperties; +import org.opensaml.xml.encryption.XMLEncryptionBuilder; +import org.opensaml.xml.util.XMLConstants; + +/** + * Builder of {@link org.opensaml.xml.encryption.EncryptionProperties}. + */ +public class EncryptionPropertiesBuilder extends AbstractXMLObjectBuilder + implements XMLEncryptionBuilder { + + /** + * Constructor. + * + */ + public EncryptionPropertiesBuilder() { + } + + /** {@inheritDoc} */ + public EncryptionProperties buildObject(String namespaceURI, String localName, String namespacePrefix) { + return new EncryptionPropertiesImpl(namespaceURI, localName, namespacePrefix); + } + + /** {@inheritDoc} */ + public EncryptionProperties buildObject() { + return buildObject(XMLConstants.XMLENC_NS, EncryptionProperties.DEFAULT_ELEMENT_LOCAL_NAME, XMLConstants.XMLENC_PREFIX); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/EncryptionPropertiesImpl.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/EncryptionPropertiesImpl.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/EncryptionPropertiesImpl.java 17 Aug 2012 15:17:13 -0000 1.1 @@ -0,0 +1,83 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption.impl; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.encryption.EncryptionProperties; +import org.opensaml.xml.encryption.EncryptionProperty; +import org.opensaml.xml.util.XMLObjectChildrenList; +import org.opensaml.xml.validation.AbstractValidatingXMLObject; + +/** + * Concrete implementation of {@link org.opensaml.xml.encryption.EncryptionProperties}. + */ +public class EncryptionPropertiesImpl extends AbstractValidatingXMLObject implements EncryptionProperties { + + /** Id attribute value. */ + private String id; + + /** EncryptionProperty child elements. */ + private final XMLObjectChildrenList encryptionProperties; + + /** + * Constructor. + * + * @param namespaceURI + * @param elementLocalName + * @param namespacePrefix + */ + protected EncryptionPropertiesImpl(String namespaceURI, String elementLocalName, String namespacePrefix) { + super(namespaceURI, elementLocalName, namespacePrefix); + encryptionProperties = new XMLObjectChildrenList(this); + } + + /** {@inheritDoc} */ + public String getID() { + return this.id; + } + + /** {@inheritDoc} */ + public void setID(String newID) { + String oldID = this.id; + this.id = prepareForAssignment(this.id, newID); + registerOwnID(oldID, this.id); + } + + /** {@inheritDoc} */ + public List getEncryptionProperties() { + return (List) encryptionProperties; + } + + /** {@inheritDoc} */ + public List getOrderedChildren() { + ArrayList children = new ArrayList(); + + children.addAll((List) encryptionProperties); + + if (children.size() == 0) { + return null; + } + + return Collections.unmodifiableList(children); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/EncryptionPropertiesMarshaller.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/EncryptionPropertiesMarshaller.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/EncryptionPropertiesMarshaller.java 17 Aug 2012 15:17:12 -0000 1.1 @@ -0,0 +1,41 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption.impl; + +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.encryption.EncryptionProperties; +import org.opensaml.xml.io.MarshallingException; +import org.w3c.dom.Element; + +/** + * A thread-safe Marshaller for {@link org.opensaml.xml.encryption.EncryptionProperties} objects. + */ +public class EncryptionPropertiesMarshaller extends AbstractXMLEncryptionMarshaller { + + /** {@inheritDoc} */ + protected void marshallAttributes(XMLObject xmlObject, Element domElement) throws MarshallingException { + EncryptionProperties ep = (EncryptionProperties) xmlObject; + + if (ep.getID() != null) { + domElement.setAttributeNS(null, EncryptionProperties.ID_ATTRIB_NAME, ep.getID()); + domElement.setIdAttributeNS(null, EncryptionProperties.ID_ATTRIB_NAME, true); + } + + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/EncryptionPropertiesUnmarshaller.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/EncryptionPropertiesUnmarshaller.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/EncryptionPropertiesUnmarshaller.java 17 Aug 2012 15:17:11 -0000 1.1 @@ -0,0 +1,55 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption.impl; + +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.encryption.EncryptionProperties; +import org.opensaml.xml.encryption.EncryptionProperty; +import org.opensaml.xml.io.UnmarshallingException; +import org.w3c.dom.Attr; + +/** + * A thread-safe Unmarshaller for {@link org.opensaml.xml.encryption.EncryptionProperties} objects. + */ +public class EncryptionPropertiesUnmarshaller extends AbstractXMLEncryptionUnmarshaller { + + /** {@inheritDoc} */ + protected void processAttribute(XMLObject xmlObject, Attr attribute) throws UnmarshallingException { + EncryptionProperties ep = (EncryptionProperties) xmlObject; + + if (attribute.getLocalName().equals(EncryptionProperties.ID_ATTRIB_NAME)) { + ep.setID(attribute.getValue()); + attribute.getOwnerElement().setIdAttributeNode(attribute, true); + } else { + super.processAttribute(xmlObject, attribute); + } + } + + /** {@inheritDoc} */ + protected void processChildElement(XMLObject parentXMLObject, XMLObject childXMLObject) + throws UnmarshallingException { + EncryptionProperties ep = (EncryptionProperties) parentXMLObject; + + if (childXMLObject instanceof EncryptionProperty) { + ep.getEncryptionProperties().add((EncryptionProperty) childXMLObject); + } else { + super.processChildElement(parentXMLObject, childXMLObject); + } + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/EncryptionPropertyBuilder.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/EncryptionPropertyBuilder.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/EncryptionPropertyBuilder.java 17 Aug 2012 15:17:11 -0000 1.1 @@ -0,0 +1,48 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption.impl; + +import org.opensaml.xml.AbstractXMLObjectBuilder; +import org.opensaml.xml.encryption.EncryptionProperty; +import org.opensaml.xml.encryption.XMLEncryptionBuilder; +import org.opensaml.xml.util.XMLConstants; + +/** + * Builder of {@link org.opensaml.xml.encryption.EncryptionProperty} + */ +public class EncryptionPropertyBuilder extends AbstractXMLObjectBuilder + implements XMLEncryptionBuilder { + + /** + * Constructor + * + */ + public EncryptionPropertyBuilder() { + } + + /** {@inheritDoc} */ + public EncryptionProperty buildObject(String namespaceURI, String localName, String namespacePrefix) { + return new EncryptionPropertyImpl(namespaceURI, localName, namespacePrefix); + } + + /** {@inheritDoc} */ + public EncryptionProperty buildObject() { + return buildObject(XMLConstants.XMLENC_NS, EncryptionProperty.DEFAULT_ELEMENT_LOCAL_NAME, XMLConstants.XMLENC_PREFIX); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/EncryptionPropertyImpl.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/EncryptionPropertyImpl.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/EncryptionPropertyImpl.java 17 Aug 2012 15:17:11 -0000 1.1 @@ -0,0 +1,111 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption.impl; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import javax.xml.namespace.QName; + +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.util.AttributeMap; +import org.opensaml.xml.util.IndexedXMLObjectChildrenList; +import org.opensaml.xml.validation.AbstractValidatingXMLObject; + +/** + * Concrete implementation of {@link org.opensaml.xml.encryption.EncryptionProperty} + */ +public class EncryptionPropertyImpl extends AbstractValidatingXMLObject implements + org.opensaml.xml.encryption.EncryptionProperty { + + /** Target attribute value */ + private String target; + + /** Id attribute value */ + private String id; + + /** Child elements from the <any> content model */ + private final IndexedXMLObjectChildrenList unknownChildren; + + /** "anyAttribute" attributes */ + private final AttributeMap unknownAttributes; + + /** + * Constructor + * + * @param namespaceURI + * @param elementLocalName + * @param namespacePrefix + */ + protected EncryptionPropertyImpl(String namespaceURI, String elementLocalName, String namespacePrefix) { + super(namespaceURI, elementLocalName, namespacePrefix); + unknownChildren = new IndexedXMLObjectChildrenList(this); + unknownAttributes = new AttributeMap(this); + } + + /** {@inheritDoc} */ + public String getTarget() { + return this.target; + } + + /** {@inheritDoc} */ + public void setTarget(String newTarget) { + this.target = prepareForAssignment(this.target, newTarget); + } + + /** {@inheritDoc} */ + public String getID() { + return this.id; + } + + /** {@inheritDoc} */ + public void setID(String newID) { + String oldID = this.id; + this.id = prepareForAssignment(this.id, newID); + registerOwnID(oldID, this.id); + } + + /** {@inheritDoc} */ + public AttributeMap getUnknownAttributes() { + return unknownAttributes; + } + + /** {@inheritDoc} */ + public List getUnknownXMLObjects() { + return (List) unknownChildren; + } + /** {@inheritDoc} */ + public List getUnknownXMLObjects(QName typeOrName) { + return (List) unknownChildren.subList(typeOrName); + } + + /** {@inheritDoc} */ + public List getOrderedChildren() { + ArrayList children = new ArrayList(); + + children.addAll((List) unknownChildren); + + if (children.size() == 0) { + return null; + } + + return Collections.unmodifiableList(children); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/EncryptionPropertyMarshaller.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/EncryptionPropertyMarshaller.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/EncryptionPropertyMarshaller.java 17 Aug 2012 15:17:12 -0000 1.1 @@ -0,0 +1,60 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption.impl; + +import java.util.Map.Entry; + +import javax.xml.namespace.QName; + +import org.opensaml.xml.Configuration; +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.encryption.EncryptionProperty; +import org.opensaml.xml.io.MarshallingException; +import org.opensaml.xml.util.XMLHelper; +import org.w3c.dom.Attr; +import org.w3c.dom.Element; + +/** + * A thread-safe Marshaller for {@link org.opensaml.xml.encryption.EncryptionProperty} objects. + */ +public class EncryptionPropertyMarshaller extends AbstractXMLEncryptionMarshaller { + + /** {@inheritDoc} */ + protected void marshallAttributes(XMLObject xmlObject, Element domElement) throws MarshallingException { + EncryptionProperty ep = (EncryptionProperty) xmlObject; + + if (ep.getID() != null) { + domElement.setAttributeNS(null, EncryptionProperty.ID_ATTRIB_NAME, ep.getID()); + domElement.setIdAttributeNS(null, EncryptionProperty.ID_ATTRIB_NAME, true); + } + if (ep.getTarget() != null) { + domElement.setAttributeNS(null, EncryptionProperty.TARGET_ATTRIB_NAME, ep.getTarget()); + } + + Attr attribute; + for (Entry entry : ep.getUnknownAttributes().entrySet()) { + attribute = XMLHelper.constructAttribute(domElement.getOwnerDocument(), entry.getKey()); + attribute.setValue(entry.getValue()); + domElement.setAttributeNodeNS(attribute); + if (Configuration.isIDAttribute(entry.getKey()) || ep.getUnknownAttributes().isIDAttribute(entry.getKey())) { + attribute.getOwnerElement().setIdAttributeNode(attribute, true); + } + } + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/EncryptionPropertyUnmarshaller.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/EncryptionPropertyUnmarshaller.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/EncryptionPropertyUnmarshaller.java 17 Aug 2012 15:17:12 -0000 1.1 @@ -0,0 +1,60 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption.impl; + +import javax.xml.namespace.QName; + +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.encryption.EncryptionProperty; +import org.opensaml.xml.io.UnmarshallingException; +import org.opensaml.xml.util.XMLHelper; +import org.w3c.dom.Attr; + +/** + * A thread-safe Unmarshaller for {@link org.opensaml.xml.encryption.EncryptionProperty} objects. + */ +public class EncryptionPropertyUnmarshaller extends AbstractXMLEncryptionUnmarshaller { + + /** {@inheritDoc} */ + protected void processAttribute(XMLObject xmlObject, Attr attribute) throws UnmarshallingException { + EncryptionProperty ep = (EncryptionProperty) xmlObject; + + if (attribute.getLocalName().equals(EncryptionProperty.ID_ATTRIB_NAME)) { + ep.setID(attribute.getValue()); + attribute.getOwnerElement().setIdAttributeNode(attribute, true); + } else if (attribute.getLocalName().equals(EncryptionProperty.TARGET_ATTRIB_NAME)) { + ep.setTarget(attribute.getValue()); + } else { + QName attributeName = XMLHelper.getNodeQName(attribute); + if (attribute.isId()) { + ep.getUnknownAttributes().registerID(attributeName); + } + ep.getUnknownAttributes().put(attributeName, attribute.getValue()); + } + } + + /** {@inheritDoc} */ + protected void processChildElement(XMLObject parentXMLObject, XMLObject childXMLObject) + throws UnmarshallingException { + EncryptionProperty ep = (EncryptionProperty) parentXMLObject; + + // content model + ep.getUnknownXMLObjects().add(childXMLObject); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/GeneratorBuilder.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/GeneratorBuilder.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/GeneratorBuilder.java 17 Aug 2012 15:17:13 -0000 1.1 @@ -0,0 +1,47 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption.impl; + +import org.opensaml.xml.AbstractXMLObjectBuilder; +import org.opensaml.xml.encryption.Generator; +import org.opensaml.xml.encryption.XMLEncryptionBuilder; +import org.opensaml.xml.util.XMLConstants; + +/** + * Builder of {@link org.opensaml.xml.encryption.Generator}. + */ +public class GeneratorBuilder extends AbstractXMLObjectBuilder implements XMLEncryptionBuilder { + + /** + * Constructor. + * + */ + public GeneratorBuilder() { + } + + /** {@inheritDoc} */ + public Generator buildObject(String namespaceURI, String localName, String namespacePrefix) { + return new GeneratorImpl(namespaceURI, localName, namespacePrefix); + } + + /** {@inheritDoc} */ + public Generator buildObject() { + return buildObject(XMLConstants.XMLENC_NS, Generator.DEFAULT_ELEMENT_LOCAL_NAME, XMLConstants.XMLENC_PREFIX); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/GeneratorImpl.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/GeneratorImpl.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/GeneratorImpl.java 17 Aug 2012 15:17:10 -0000 1.1 @@ -0,0 +1,40 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption.impl; + +import org.opensaml.xml.encryption.Generator; +import org.opensaml.xml.signature.impl.CryptoBinaryImpl; + + +/** + * Concrete implementation of {@link org.opensaml.xml.encryption.Generator} + */ +public class GeneratorImpl extends CryptoBinaryImpl implements Generator { + + /** + * Constructor + * + * @param namespaceURI + * @param elementLocalName + * @param namespacePrefix + */ + protected GeneratorImpl(String namespaceURI, String elementLocalName, String namespacePrefix) { + super(namespaceURI, elementLocalName, namespacePrefix); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/KANonceBuilder.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/KANonceBuilder.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/KANonceBuilder.java 17 Aug 2012 15:17:10 -0000 1.1 @@ -0,0 +1,47 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption.impl; + +import org.opensaml.xml.AbstractXMLObjectBuilder; +import org.opensaml.xml.encryption.KANonce; +import org.opensaml.xml.encryption.XMLEncryptionBuilder; +import org.opensaml.xml.util.XMLConstants; + +/** + * Builder of {@link org.opensaml.xml.encryption.KANonce} + */ +public class KANonceBuilder extends AbstractXMLObjectBuilder implements XMLEncryptionBuilder { + + /** + * Constructor + * + */ + public KANonceBuilder() { + } + + /** {@inheritDoc} */ + public KANonce buildObject(String namespaceURI, String localName, String namespacePrefix) { + return new KANonceImpl(namespaceURI, localName, namespacePrefix); + } + + /** {@inheritDoc} */ + public KANonce buildObject() { + return buildObject(XMLConstants.XMLENC_NS, KANonce.DEFAULT_ELEMENT_LOCAL_NAME, XMLConstants.XMLENC_PREFIX); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/KANonceImpl.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/KANonceImpl.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/KANonceImpl.java 17 Aug 2012 15:17:11 -0000 1.1 @@ -0,0 +1,39 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption.impl; + +import org.opensaml.xml.encryption.KANonce; +import org.opensaml.xml.schema.impl.XSBase64BinaryImpl; + +/** + * Concrete implementation of {@link org.opensaml.xml.encryption.KANonce} + */ +public class KANonceImpl extends XSBase64BinaryImpl implements KANonce { + + /** + * Constructor + * + * @param namespaceURI + * @param elementLocalName + * @param namespacePrefix + */ + protected KANonceImpl(String namespaceURI, String elementLocalName, String namespacePrefix) { + super(namespaceURI, elementLocalName, namespacePrefix); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/KeyReferenceBuilder.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/KeyReferenceBuilder.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/KeyReferenceBuilder.java 17 Aug 2012 15:17:11 -0000 1.1 @@ -0,0 +1,47 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption.impl; + +import org.opensaml.xml.AbstractXMLObjectBuilder; +import org.opensaml.xml.encryption.KeyReference; +import org.opensaml.xml.encryption.XMLEncryptionBuilder; +import org.opensaml.xml.util.XMLConstants; + +/** + * Builder of {@link org.opensaml.xml.encryption.KeyReference} + */ +public class KeyReferenceBuilder extends AbstractXMLObjectBuilder implements XMLEncryptionBuilder { + + /** + * Constructor + * + */ + public KeyReferenceBuilder() { + } + + /** {@inheritDoc} */ + public KeyReference buildObject(String namespaceURI, String localName, String namespacePrefix) { + return new KeyReferenceImpl(namespaceURI, localName, namespacePrefix); + } + + /** {@inheritDoc} */ + public KeyReference buildObject() { + return buildObject(XMLConstants.XMLENC_NS, KeyReference.DEFAULT_ELEMENT_LOCAL_NAME, XMLConstants.XMLENC_PREFIX); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/KeyReferenceImpl.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/KeyReferenceImpl.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/KeyReferenceImpl.java 17 Aug 2012 15:17:10 -0000 1.1 @@ -0,0 +1,38 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption.impl; + +import org.opensaml.xml.encryption.KeyReference; + +/** + * + */ +public class KeyReferenceImpl extends ReferenceTypeImpl implements KeyReference { + + /** + * Constructor + * + * @param namespaceURI + * @param elementLocalName + * @param namespacePrefix + */ + protected KeyReferenceImpl(String namespaceURI, String elementLocalName, String namespacePrefix) { + super(namespaceURI, elementLocalName, namespacePrefix); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/KeyReferenceMarshaller.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/KeyReferenceMarshaller.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/KeyReferenceMarshaller.java 17 Aug 2012 15:17:11 -0000 1.1 @@ -0,0 +1,25 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption.impl; + +/** + * A thread-safe Marshaller for {@link org.opensaml.xml.encryption.KeyReference} objects. + */ +public class KeyReferenceMarshaller extends ReferenceTypeMarshaller { + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/KeyReferenceUnmarshaller.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/KeyReferenceUnmarshaller.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/KeyReferenceUnmarshaller.java 17 Aug 2012 15:17:12 -0000 1.1 @@ -0,0 +1,25 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption.impl; + +/** + * A thread-safe Unmarshaller for {@link org.opensaml.xml.encryption.KeyReference} objects. + */ +public class KeyReferenceUnmarshaller extends ReferenceTypeUnmarshaller { + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/KeySizeBuilder.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/KeySizeBuilder.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/KeySizeBuilder.java 17 Aug 2012 15:17:11 -0000 1.1 @@ -0,0 +1,47 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption.impl; + +import org.opensaml.xml.AbstractXMLObjectBuilder; +import org.opensaml.xml.encryption.KeySize; +import org.opensaml.xml.encryption.XMLEncryptionBuilder; +import org.opensaml.xml.util.XMLConstants; + +/** + * Builder of {@link org.opensaml.xml.encryption.KeySize} + */ +public class KeySizeBuilder extends AbstractXMLObjectBuilder implements XMLEncryptionBuilder { + + /** + * Constructor + * + */ + public KeySizeBuilder() { + } + + /** {@inheritDoc} */ + public KeySize buildObject(String namespaceURI, String localName, String namespacePrefix) { + return new KeySizeImpl(namespaceURI, localName, namespacePrefix); + } + + /** {@inheritDoc} */ + public KeySize buildObject() { + return buildObject(XMLConstants.XMLENC_NS, KeySize.DEFAULT_ELEMENT_LOCAL_NAME, XMLConstants.XMLENC_PREFIX); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/KeySizeImpl.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/KeySizeImpl.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/KeySizeImpl.java 17 Aug 2012 15:17:12 -0000 1.1 @@ -0,0 +1,39 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption.impl; + +import org.opensaml.xml.encryption.KeySize; +import org.opensaml.xml.schema.impl.XSIntegerImpl; + +/** + * Concrete implementation of {@link org.opensaml.xml.encryption.KeySize} + */ +public class KeySizeImpl extends XSIntegerImpl implements KeySize { + + /** + * Constructor + * + * @param namespaceURI + * @param elementLocalName + * @param namespacePrefix + */ + protected KeySizeImpl(String namespaceURI, String elementLocalName, String namespacePrefix) { + super(namespaceURI, elementLocalName, namespacePrefix); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/OAEPparamsBuilder.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/OAEPparamsBuilder.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/OAEPparamsBuilder.java 17 Aug 2012 15:17:10 -0000 1.1 @@ -0,0 +1,47 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption.impl; + +import org.opensaml.xml.AbstractXMLObjectBuilder; +import org.opensaml.xml.encryption.OAEPparams; +import org.opensaml.xml.encryption.XMLEncryptionBuilder; +import org.opensaml.xml.util.XMLConstants; + +/** + * Builder of {@link org.opensaml.xml.encryption.OAEPparams} + */ +public class OAEPparamsBuilder extends AbstractXMLObjectBuilder implements XMLEncryptionBuilder { + + /** + * Constructor + * + */ + public OAEPparamsBuilder() { + } + + /** {@inheritDoc} */ + public OAEPparams buildObject(String namespaceURI, String localName, String namespacePrefix) { + return new OAEPparamsImpl(namespaceURI, localName, namespacePrefix); + } + + /** {@inheritDoc} */ + public OAEPparams buildObject() { + return buildObject(XMLConstants.XMLENC_NS, OAEPparams.DEFAULT_ELEMENT_LOCAL_NAME, XMLConstants.XMLENC_PREFIX); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/OAEPparamsImpl.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/OAEPparamsImpl.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/OAEPparamsImpl.java 17 Aug 2012 15:17:12 -0000 1.1 @@ -0,0 +1,39 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption.impl; + +import org.opensaml.xml.encryption.OAEPparams; +import org.opensaml.xml.schema.impl.XSBase64BinaryImpl; + +/** + * Concrete implementation of {@link org.opensaml.xml.encryption.OAEPparams} + */ +public class OAEPparamsImpl extends XSBase64BinaryImpl implements OAEPparams { + + /** + * Constructor + * + * @param namespaceURI + * @param elementLocalName + * @param namespacePrefix + */ + protected OAEPparamsImpl(String namespaceURI, String elementLocalName, String namespacePrefix) { + super(namespaceURI, elementLocalName, namespacePrefix); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/OriginatorKeyInfoBuilder.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/OriginatorKeyInfoBuilder.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/OriginatorKeyInfoBuilder.java 17 Aug 2012 15:17:11 -0000 1.1 @@ -0,0 +1,48 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption.impl; + +import org.opensaml.xml.AbstractXMLObjectBuilder; +import org.opensaml.xml.encryption.OriginatorKeyInfo; +import org.opensaml.xml.encryption.XMLEncryptionBuilder; +import org.opensaml.xml.util.XMLConstants; + +/** + * Builder of {@link org.opensaml.xml.encryption.OriginatorKeyInfo} + */ +public class OriginatorKeyInfoBuilder extends AbstractXMLObjectBuilder + implements XMLEncryptionBuilder { + + /** + * Constructor + * + */ + public OriginatorKeyInfoBuilder() { + } + + /** {@inheritDoc} */ + public OriginatorKeyInfo buildObject(String namespaceURI, String localName, String namespacePrefix) { + return new OriginatorKeyInfoImpl(namespaceURI, localName, namespacePrefix); + } + + /** {@inheritDoc} */ + public OriginatorKeyInfo buildObject() { + return buildObject(XMLConstants.XMLENC_NS, OriginatorKeyInfo.DEFAULT_ELEMENT_LOCAL_NAME, XMLConstants.XMLENC_PREFIX); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/OriginatorKeyInfoImpl.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/OriginatorKeyInfoImpl.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/OriginatorKeyInfoImpl.java 17 Aug 2012 15:17:12 -0000 1.1 @@ -0,0 +1,39 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption.impl; + +import org.opensaml.xml.encryption.OriginatorKeyInfo; +import org.opensaml.xml.signature.impl.KeyInfoTypeImpl; + +/** + * Concrete implementation of {@link org.opensaml.xml.encryption.OriginatorKeyInfo} + */ +public class OriginatorKeyInfoImpl extends KeyInfoTypeImpl implements OriginatorKeyInfo { + + /** + * Constructor + * + * @param namespaceURI + * @param elementLocalName + * @param namespacePrefix + */ + protected OriginatorKeyInfoImpl(String namespaceURI, String elementLocalName, String namespacePrefix) { + super(namespaceURI, elementLocalName, namespacePrefix); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/OriginatorKeyInfoMarshaller.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/OriginatorKeyInfoMarshaller.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/OriginatorKeyInfoMarshaller.java 17 Aug 2012 15:17:12 -0000 1.1 @@ -0,0 +1,27 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption.impl; + +import org.opensaml.xml.signature.impl.KeyInfoTypeMarshaller; + +/** + * A thread-safe Marshaller for {@link org.opensaml.xml.encryption.OriginatorKeyInfo} objects. + */ +public class OriginatorKeyInfoMarshaller extends KeyInfoTypeMarshaller { + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/OriginatorKeyInfoUnmarshaller.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/OriginatorKeyInfoUnmarshaller.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/OriginatorKeyInfoUnmarshaller.java 17 Aug 2012 15:17:12 -0000 1.1 @@ -0,0 +1,27 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption.impl; + +import org.opensaml.xml.signature.impl.KeyInfoTypeUnmarshaller; + +/** + * A thread-safe Unmarshaller for {@link org.opensaml.xml.encryption.OriginatorKeyInfo} objects. + */ +public class OriginatorKeyInfoUnmarshaller extends KeyInfoTypeUnmarshaller { + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/PBuilder.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/PBuilder.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/PBuilder.java 17 Aug 2012 15:17:10 -0000 1.1 @@ -0,0 +1,47 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption.impl; + +import org.opensaml.xml.AbstractXMLObjectBuilder; +import org.opensaml.xml.encryption.P; +import org.opensaml.xml.encryption.XMLEncryptionBuilder; +import org.opensaml.xml.util.XMLConstants; + +/** + * Builder of {@link org.opensaml.xml.signature.P} + */ +public class PBuilder extends AbstractXMLObjectBuilder

implements XMLEncryptionBuilder

{ + + /** + * Constructor + * + */ + public PBuilder() { + } + + /** {@inheritDoc} */ + public P buildObject(String namespaceURI, String localName, String namespacePrefix) { + return new PImpl(namespaceURI, localName, namespacePrefix); + } + + /** {@inheritDoc} */ + public P buildObject() { + return buildObject(XMLConstants.XMLENC_NS, P.DEFAULT_ELEMENT_LOCAL_NAME, XMLConstants.XMLENC_PREFIX); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/PImpl.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/PImpl.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/PImpl.java 17 Aug 2012 15:17:12 -0000 1.1 @@ -0,0 +1,40 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption.impl; + +import org.opensaml.xml.encryption.P; +import org.opensaml.xml.signature.impl.CryptoBinaryImpl; + + +/** + * Concrete implementation of {@link org.opensaml.xml.encryption.P} + */ +public class PImpl extends CryptoBinaryImpl implements P { + + /** + * Constructor + * + * @param namespaceURI + * @param elementLocalName + * @param namespacePrefix + */ + protected PImpl(String namespaceURI, String elementLocalName, String namespacePrefix) { + super(namespaceURI, elementLocalName, namespacePrefix); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/PgenCounterBuilder.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/PgenCounterBuilder.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/PgenCounterBuilder.java 17 Aug 2012 15:17:12 -0000 1.1 @@ -0,0 +1,47 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption.impl; + +import org.opensaml.xml.AbstractXMLObjectBuilder; +import org.opensaml.xml.encryption.PgenCounter; +import org.opensaml.xml.encryption.XMLEncryptionBuilder; +import org.opensaml.xml.util.XMLConstants; + +/** + * Builder of {@link org.opensaml.xml.encryption.PgenCounter} + */ +public class PgenCounterBuilder extends AbstractXMLObjectBuilder implements XMLEncryptionBuilder { + + /** + * Constructor + * + */ + public PgenCounterBuilder() { + } + + /** {@inheritDoc} */ + public PgenCounter buildObject(String namespaceURI, String localName, String namespacePrefix) { + return new PgenCounterImpl(namespaceURI, localName, namespacePrefix); + } + + /** {@inheritDoc} */ + public PgenCounter buildObject() { + return buildObject(XMLConstants.XMLENC_NS, PgenCounter.DEFAULT_ELEMENT_LOCAL_NAME, XMLConstants.XMLENC_PREFIX); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/PgenCounterImpl.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/PgenCounterImpl.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/PgenCounterImpl.java 17 Aug 2012 15:17:10 -0000 1.1 @@ -0,0 +1,40 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption.impl; + +import org.opensaml.xml.encryption.PgenCounter; +import org.opensaml.xml.signature.impl.CryptoBinaryImpl; + + +/** + * Concrete implementation of {@link org.opensaml.xml.encryption.PgenCounter} + */ +public class PgenCounterImpl extends CryptoBinaryImpl implements PgenCounter { + + /** + * Constructor + * + * @param namespaceURI + * @param elementLocalName + * @param namespacePrefix + */ + protected PgenCounterImpl(String namespaceURI, String elementLocalName, String namespacePrefix) { + super(namespaceURI, elementLocalName, namespacePrefix); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/PublicBuilder.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/PublicBuilder.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/PublicBuilder.java 17 Aug 2012 15:17:12 -0000 1.1 @@ -0,0 +1,47 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption.impl; + +import org.opensaml.xml.AbstractXMLObjectBuilder; +import org.opensaml.xml.encryption.Public; +import org.opensaml.xml.encryption.XMLEncryptionBuilder; +import org.opensaml.xml.util.XMLConstants; + +/** + * Builder of {@link org.opensaml.xml.encryption.Public} + */ +public class PublicBuilder extends AbstractXMLObjectBuilder implements XMLEncryptionBuilder { + + /** + * Constructor + * + */ + public PublicBuilder() { + } + + /** {@inheritDoc} */ + public Public buildObject(String namespaceURI, String localName, String namespacePrefix) { + return new PublicImpl(namespaceURI, localName, namespacePrefix); + } + + /** {@inheritDoc} */ + public Public buildObject() { + return buildObject(XMLConstants.XMLENC_NS, Public.DEFAULT_ELEMENT_LOCAL_NAME, XMLConstants.XMLENC_PREFIX); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/PublicImpl.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/PublicImpl.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/PublicImpl.java 17 Aug 2012 15:17:12 -0000 1.1 @@ -0,0 +1,40 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption.impl; + +import org.opensaml.xml.encryption.Public; +import org.opensaml.xml.signature.impl.CryptoBinaryImpl; + + +/** + * Concrete implementation of {@link org.opensaml.xml.encryption.Public} + */ +public class PublicImpl extends CryptoBinaryImpl implements Public { + + /** + * Constructor + * + * @param namespaceURI + * @param elementLocalName + * @param namespacePrefix + */ + protected PublicImpl(String namespaceURI, String elementLocalName, String namespacePrefix) { + super(namespaceURI, elementLocalName, namespacePrefix); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/QBuilder.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/QBuilder.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/QBuilder.java 17 Aug 2012 15:17:11 -0000 1.1 @@ -0,0 +1,47 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption.impl; + +import org.opensaml.xml.AbstractXMLObjectBuilder; +import org.opensaml.xml.encryption.Q; +import org.opensaml.xml.encryption.XMLEncryptionBuilder; +import org.opensaml.xml.util.XMLConstants; + +/** + * Builder of {@link org.opensaml.xml.encryption.Q} + */ +public class QBuilder extends AbstractXMLObjectBuilder implements XMLEncryptionBuilder { + + /** + * Constructor + * + */ + public QBuilder() { + } + + /** {@inheritDoc} */ + public Q buildObject(String namespaceURI, String localName, String namespacePrefix) { + return new QImpl(namespaceURI, localName, namespacePrefix); + } + + /** {@inheritDoc} */ + public Q buildObject() { + return buildObject(XMLConstants.XMLENC_NS, Q.DEFAULT_ELEMENT_LOCAL_NAME, XMLConstants.XMLENC_PREFIX); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/QImpl.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/QImpl.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/QImpl.java 17 Aug 2012 15:17:13 -0000 1.1 @@ -0,0 +1,40 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption.impl; + +import org.opensaml.xml.encryption.Q; +import org.opensaml.xml.signature.impl.CryptoBinaryImpl; + + +/** + * Concrete implementation of {@link org.opensaml.xml.encryption.Q} + */ +public class QImpl extends CryptoBinaryImpl implements Q { + + /** + * Constructor + * + * @param namespaceURI + * @param elementLocalName + * @param namespacePrefix + */ + protected QImpl(String namespaceURI, String elementLocalName, String namespacePrefix) { + super(namespaceURI, elementLocalName, namespacePrefix); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/RecipientKeyInfoBuilder.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/RecipientKeyInfoBuilder.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/RecipientKeyInfoBuilder.java 17 Aug 2012 15:17:10 -0000 1.1 @@ -0,0 +1,48 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption.impl; + +import org.opensaml.xml.AbstractXMLObjectBuilder; +import org.opensaml.xml.encryption.RecipientKeyInfo; +import org.opensaml.xml.encryption.XMLEncryptionBuilder; +import org.opensaml.xml.util.XMLConstants; + +/** + * Builder of {@link org.opensaml.xml.encryption.ReferenceList} + */ +public class RecipientKeyInfoBuilder extends AbstractXMLObjectBuilder + implements XMLEncryptionBuilder { + + /** + * Constructor + * + */ + public RecipientKeyInfoBuilder() { + } + + /** {@inheritDoc} */ + public RecipientKeyInfo buildObject(String namespaceURI, String localName, String namespacePrefix) { + return new RecipientKeyInfoImpl(namespaceURI, localName, namespacePrefix); + } + + /** {@inheritDoc} */ + public RecipientKeyInfo buildObject() { + return buildObject(XMLConstants.XMLENC_NS, RecipientKeyInfo.DEFAULT_ELEMENT_LOCAL_NAME, XMLConstants.XMLENC_PREFIX); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/RecipientKeyInfoImpl.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/RecipientKeyInfoImpl.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/RecipientKeyInfoImpl.java 17 Aug 2012 15:17:11 -0000 1.1 @@ -0,0 +1,39 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption.impl; + +import org.opensaml.xml.encryption.RecipientKeyInfo; +import org.opensaml.xml.signature.impl.KeyInfoTypeImpl; + +/** + * Concrete implementation of {@link org.opensaml.xml.encryption.RecipientKeyInfo} + */ +public class RecipientKeyInfoImpl extends KeyInfoTypeImpl implements RecipientKeyInfo { + + /** + * Constructor + * + * @param namespaceURI + * @param elementLocalName + * @param namespacePrefix + */ + protected RecipientKeyInfoImpl(String namespaceURI, String elementLocalName, String namespacePrefix) { + super(namespaceURI, elementLocalName, namespacePrefix); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/RecipientKeyInfoMarshaller.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/RecipientKeyInfoMarshaller.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/RecipientKeyInfoMarshaller.java 17 Aug 2012 15:17:13 -0000 1.1 @@ -0,0 +1,27 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption.impl; + +import org.opensaml.xml.signature.impl.KeyInfoTypeMarshaller; + +/** + * A thread-safe Marshaller for {@link org.opensaml.xml.encryption.RecipientKeyInfo} objects. + */ +public class RecipientKeyInfoMarshaller extends KeyInfoTypeMarshaller { + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/RecipientKeyInfoUnmarshaller.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/RecipientKeyInfoUnmarshaller.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/RecipientKeyInfoUnmarshaller.java 17 Aug 2012 15:17:13 -0000 1.1 @@ -0,0 +1,27 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption.impl; + +import org.opensaml.xml.signature.impl.KeyInfoTypeUnmarshaller; + +/** + * A thread-safe Unmarshaller for {@link org.opensaml.xml.encryption.RecipientKeyInfo} objects. + */ +public class RecipientKeyInfoUnmarshaller extends KeyInfoTypeUnmarshaller { + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/ReferenceListBuilder.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/ReferenceListBuilder.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/ReferenceListBuilder.java 17 Aug 2012 15:17:12 -0000 1.1 @@ -0,0 +1,48 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption.impl; + +import org.opensaml.xml.AbstractXMLObjectBuilder; +import org.opensaml.xml.encryption.ReferenceList; +import org.opensaml.xml.encryption.XMLEncryptionBuilder; +import org.opensaml.xml.util.XMLConstants; + +/** + * Builder of {@link org.opensaml.xml.encryption.ReferenceList} + */ +public class ReferenceListBuilder extends AbstractXMLObjectBuilder + implements XMLEncryptionBuilder { + + /** + * Constructor + * + */ + public ReferenceListBuilder() { + } + + /** {@inheritDoc} */ + public ReferenceList buildObject(String namespaceURI, String localName, String namespacePrefix) { + return new ReferenceListImpl(namespaceURI, localName, namespacePrefix); + } + + /** {@inheritDoc} */ + public ReferenceList buildObject() { + return buildObject(XMLConstants.XMLENC_NS, ReferenceList.DEFAULT_ELEMENT_LOCAL_NAME, XMLConstants.XMLENC_PREFIX); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/ReferenceListImpl.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/ReferenceListImpl.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/ReferenceListImpl.java 17 Aug 2012 15:17:10 -0000 1.1 @@ -0,0 +1,80 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption.impl; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.encryption.DataReference; +import org.opensaml.xml.encryption.KeyReference; +import org.opensaml.xml.encryption.ReferenceList; +import org.opensaml.xml.encryption.ReferenceType; +import org.opensaml.xml.util.IndexedXMLObjectChildrenList; +import org.opensaml.xml.validation.AbstractValidatingXMLObject; + +/** + * Concrete implementation of {@link org.opensaml.xml.encryption.ReferenceList} + */ +public class ReferenceListImpl extends AbstractValidatingXMLObject implements ReferenceList { + + /** ReferenceType child elements */ + private final IndexedXMLObjectChildrenList indexedChildren; + + /** + * Constructor + * + * @param namespaceURI + * @param elementLocalName + * @param namespacePrefix + */ + protected ReferenceListImpl(String namespaceURI, String elementLocalName, String namespacePrefix) { + super(namespaceURI, elementLocalName, namespacePrefix); + indexedChildren = new IndexedXMLObjectChildrenList(this); + } + + /** {@inheritDoc} */ + public List getReferences() { + return (List) indexedChildren; + } + + /** {@inheritDoc} */ + public List getDataReferences() { + return (List) indexedChildren.subList(DataReference.DEFAULT_ELEMENT_NAME); + } + + /** {@inheritDoc} */ + public List getKeyReferences() { + return (List) indexedChildren.subList(KeyReference.DEFAULT_ELEMENT_NAME); + } + + /** {@inheritDoc} */ + public List getOrderedChildren() { + ArrayList children = new ArrayList(); + + children.addAll((List) indexedChildren); + + if (children.size() == 0) { + return null; + } + + return Collections.unmodifiableList(children); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/ReferenceListMarshaller.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/ReferenceListMarshaller.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/ReferenceListMarshaller.java 17 Aug 2012 15:17:11 -0000 1.1 @@ -0,0 +1,25 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption.impl; + +/** + * A thread-safe Marshaller for {@link org.opensaml.xml.encryption.ReferenceList} objects. + */ +public class ReferenceListMarshaller extends AbstractXMLEncryptionMarshaller { + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/ReferenceListUnmarshaller.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/ReferenceListUnmarshaller.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/ReferenceListUnmarshaller.java 17 Aug 2012 15:17:10 -0000 1.1 @@ -0,0 +1,45 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption.impl; + +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.encryption.DataReference; +import org.opensaml.xml.encryption.KeyReference; +import org.opensaml.xml.encryption.ReferenceList; +import org.opensaml.xml.io.UnmarshallingException; + +/** + * A thread-safe Unmarshaller for {@link org.opensaml.xml.encryption.ReferenceList} objects. + */ +public class ReferenceListUnmarshaller extends AbstractXMLEncryptionUnmarshaller { + + /** {@inheritDoc} */ + protected void processChildElement(XMLObject parentXMLObject, XMLObject childXMLObject) + throws UnmarshallingException { + ReferenceList rl = (ReferenceList) parentXMLObject; + + if (childXMLObject instanceof DataReference) { + rl.getReferences().add((DataReference) childXMLObject); + } else if (childXMLObject instanceof KeyReference) { + rl.getReferences().add((KeyReference) childXMLObject); + } else { + super.processChildElement(parentXMLObject, childXMLObject); + } + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/ReferenceTypeImpl.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/ReferenceTypeImpl.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/ReferenceTypeImpl.java 17 Aug 2012 15:17:11 -0000 1.1 @@ -0,0 +1,87 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption.impl; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import javax.xml.namespace.QName; + +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.encryption.ReferenceType; +import org.opensaml.xml.util.IndexedXMLObjectChildrenList; +import org.opensaml.xml.validation.AbstractValidatingXMLObject; + +/** + * Concrete implementation of {@link org.opensaml.xml.encryption.ReferenceType} + */ +public class ReferenceTypeImpl extends AbstractValidatingXMLObject implements ReferenceType { + + /** URI attribute value */ + private String uri; + + /** List of <any> XML child elements */ + private final IndexedXMLObjectChildrenList xmlChildren; + + /** + * Constructor + * + * @param namespaceURI + * @param elementLocalName + * @param namespacePrefix + */ + protected ReferenceTypeImpl(String namespaceURI, String elementLocalName, String namespacePrefix) { + super(namespaceURI, elementLocalName, namespacePrefix); + xmlChildren = new IndexedXMLObjectChildrenList(this); + } + + /** {@inheritDoc} */ + public String getURI() { + return this.uri; + } + + /** {@inheritDoc} */ + public void setURI(String newURI) { + this.uri = prepareForAssignment(this.uri, newURI); + } + + /** {@inheritDoc} */ + public List getUnknownXMLObjects() { + return xmlChildren; + } + + /** {@inheritDoc} */ + public List getUnknownXMLObjects(QName typeOrName) { + return (List) xmlChildren.subList(typeOrName); + } + + /** {@inheritDoc} */ + public List getOrderedChildren() { + ArrayList children = new ArrayList(); + + children.addAll(xmlChildren); + + if (children.size() == 0) { + return null; + } + + return Collections.unmodifiableList(children); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/ReferenceTypeMarshaller.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/ReferenceTypeMarshaller.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/ReferenceTypeMarshaller.java 17 Aug 2012 15:17:12 -0000 1.1 @@ -0,0 +1,40 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption.impl; + +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.encryption.ReferenceType; +import org.opensaml.xml.io.MarshallingException; +import org.w3c.dom.Element; + +/** + * A thread-safe Marshaller for {@link org.opensaml.xml.encryption.ReferenceType} objects. + */ +public class ReferenceTypeMarshaller extends AbstractXMLEncryptionMarshaller { + + /** {@inheritDoc} */ + protected void marshallAttributes(XMLObject xmlObject, Element domElement) throws MarshallingException { + ReferenceType rt = (ReferenceType) xmlObject; + + if (rt.getURI() != null) { + domElement.setAttributeNS(null, ReferenceType.URI_ATTRIB_NAME, rt.getURI()); + } else { + super.marshallAttributes(xmlObject, domElement); + } + } +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/ReferenceTypeUnmarshaller.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/ReferenceTypeUnmarshaller.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/ReferenceTypeUnmarshaller.java 17 Aug 2012 15:17:11 -0000 1.1 @@ -0,0 +1,49 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption.impl; + +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.encryption.ReferenceType; +import org.opensaml.xml.io.UnmarshallingException; +import org.w3c.dom.Attr; + +/** + * A thread-safe Unmarshaller for {@link org.opensaml.xml.encryption.ReferenceType} objects. + */ +public class ReferenceTypeUnmarshaller extends AbstractXMLEncryptionUnmarshaller { + + /** {@inheritDoc} */ + protected void processAttribute(XMLObject xmlObject, Attr attribute) throws UnmarshallingException { + ReferenceType rt = (ReferenceType) xmlObject; + + if (attribute.getLocalName().equals(ReferenceType.URI_ATTRIB_NAME)) { + rt.setURI(attribute.getValue()); + } else { + super.processAttribute(xmlObject, attribute); + } + } + + /** {@inheritDoc} */ + protected void processChildElement(XMLObject parentXMLObject, XMLObject childXMLObject) + throws UnmarshallingException { + ReferenceType rt = (ReferenceType) parentXMLObject; + + rt.getUnknownXMLObjects().add(childXMLObject); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/SeedBuilder.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/SeedBuilder.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/SeedBuilder.java 17 Aug 2012 15:17:11 -0000 1.1 @@ -0,0 +1,47 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption.impl; + +import org.opensaml.xml.AbstractXMLObjectBuilder; +import org.opensaml.xml.encryption.Seed; +import org.opensaml.xml.encryption.XMLEncryptionBuilder; +import org.opensaml.xml.util.XMLConstants; + +/** + * Builder of {@link org.opensaml.xml.encryption.Seed} + */ +public class SeedBuilder extends AbstractXMLObjectBuilder implements XMLEncryptionBuilder { + + /** + * Constructor + * + */ + public SeedBuilder() { + } + + /** {@inheritDoc} */ + public Seed buildObject(String namespaceURI, String localName, String namespacePrefix) { + return new SeedImpl(namespaceURI, localName, namespacePrefix); + } + + /** {@inheritDoc} */ + public Seed buildObject() { + return buildObject(XMLConstants.XMLENC_NS, Seed.DEFAULT_ELEMENT_LOCAL_NAME, XMLConstants.XMLENC_PREFIX); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/SeedImpl.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/SeedImpl.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/SeedImpl.java 17 Aug 2012 15:17:12 -0000 1.1 @@ -0,0 +1,40 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption.impl; + +import org.opensaml.xml.encryption.Seed; +import org.opensaml.xml.signature.impl.CryptoBinaryImpl; + + +/** + * Concrete implementation of {@link org.opensaml.xml.encryption.Seed} + */ +public class SeedImpl extends CryptoBinaryImpl implements Seed { + + /** + * Constructor + * + * @param namespaceURI + * @param elementLocalName + * @param namespacePrefix + */ + protected SeedImpl(String namespaceURI, String elementLocalName, String namespacePrefix) { + super(namespaceURI, elementLocalName, namespacePrefix); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/TransformsBuilder.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/TransformsBuilder.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/TransformsBuilder.java 17 Aug 2012 15:17:10 -0000 1.1 @@ -0,0 +1,47 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption.impl; + +import org.opensaml.xml.AbstractXMLObjectBuilder; +import org.opensaml.xml.encryption.Transforms; +import org.opensaml.xml.encryption.XMLEncryptionBuilder; +import org.opensaml.xml.util.XMLConstants; + +/** + * Builder of {@link org.opensaml.xml.encryption.Transforms} + */ +public class TransformsBuilder extends AbstractXMLObjectBuilder implements XMLEncryptionBuilder { + + /** + * Constructor + * + */ + public TransformsBuilder() { + } + + /** {@inheritDoc} */ + public Transforms buildObject(String namespaceURI, String localName, String namespacePrefix) { + return new TransformsImpl(namespaceURI, localName, namespacePrefix); + } + + /** {@inheritDoc} */ + public Transforms buildObject() { + return buildObject(XMLConstants.XMLENC_NS, Transforms.DEFAULT_ELEMENT_LOCAL_NAME, XMLConstants.XMLENC_PREFIX); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/TransformsImpl.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/TransformsImpl.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/TransformsImpl.java 17 Aug 2012 15:17:11 -0000 1.1 @@ -0,0 +1,67 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption.impl; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.encryption.Transforms; +import org.opensaml.xml.signature.Transform; +import org.opensaml.xml.util.XMLObjectChildrenList; +import org.opensaml.xml.validation.AbstractValidatingXMLObject; + +/** + * Concrete implementation of {@link org.opensaml.xml.encryption.Transforms} + */ +public class TransformsImpl extends AbstractValidatingXMLObject implements Transforms { + + private final XMLObjectChildrenList transforms; + + /** + * Constructor + * + * @param namespaceURI + * @param elementLocalName + * @param namespacePrefix + */ + protected TransformsImpl(String namespaceURI, String elementLocalName, String namespacePrefix) { + super(namespaceURI, elementLocalName, namespacePrefix); + transforms = new XMLObjectChildrenList(this); + } + + /** {@inheritDoc} */ + public List getTransforms() { + return (List) this.transforms; + } + + /** {@inheritDoc} */ + public List getOrderedChildren() { + ArrayList children = new ArrayList(); + + children.addAll((List) transforms); + + if (children.size() == 0) { + return null; + } + + return Collections.unmodifiableList(children); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/TransformsMarshaller.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/TransformsMarshaller.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/TransformsMarshaller.java 17 Aug 2012 15:17:12 -0000 1.1 @@ -0,0 +1,25 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption.impl; + +/** + * A thread-safe Marshaller for {@link org.opensaml.xml.encryption.Transforms} objects. + */ +public class TransformsMarshaller extends AbstractXMLEncryptionMarshaller { + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/TransformsUnmarshaller.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/TransformsUnmarshaller.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/TransformsUnmarshaller.java 17 Aug 2012 15:17:12 -0000 1.1 @@ -0,0 +1,42 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption.impl; + +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.encryption.Transforms; +import org.opensaml.xml.io.UnmarshallingException; +import org.opensaml.xml.signature.Transform; + +/** + * A thread-safe Unmarshaller for {@link org.opensaml.xml.encryption.Transforms} objects. + */ +public class TransformsUnmarshaller extends AbstractXMLEncryptionUnmarshaller { + + /** {@inheritDoc} */ + protected void processChildElement(XMLObject parentXMLObject, XMLObject childXMLObject) + throws UnmarshallingException { + Transforms transforms = (Transforms) parentXMLObject; + + if (childXMLObject instanceof Transform) { + transforms.getTransforms().add((Transform) childXMLObject); + } else { + super.processChildElement(parentXMLObject, childXMLObject); + } + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/package.html =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/package.html,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/impl/package.html 17 Aug 2012 15:17:11 -0000 1.1 @@ -0,0 +1,5 @@ + + +Implementations of the interfaces for XMLObjects that represent XML encryption types. + + \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/validator/AgreementMethodSchemaValidator.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/validator/AgreementMethodSchemaValidator.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/validator/AgreementMethodSchemaValidator.java 17 Aug 2012 15:17:20 -0000 1.1 @@ -0,0 +1,47 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption.validator; + +import org.opensaml.xml.encryption.AgreementMethod; +import org.opensaml.xml.util.DatatypeHelper; +import org.opensaml.xml.validation.ValidationException; +import org.opensaml.xml.validation.Validator; + +/** + * Checks {@link org.opensaml.xml.encryption.AgreementMethod} for Schema compliance. + */ +public class AgreementMethodSchemaValidator implements Validator { + + /** {@inheritDoc} */ + public void validate(AgreementMethod xmlObject) throws ValidationException { + validateAlgorithm(xmlObject); + } + + /** + * Validate the algorithm URI. + * + * @param xmlObject the object to validate + * @throws ValidationException thrown if the object is invalid + */ + protected void validateAlgorithm(AgreementMethod xmlObject) throws ValidationException { + if (DatatypeHelper.isEmpty(xmlObject.getAlgorithm())) { + throw new ValidationException("AgreementMethod algorithm URI was empty"); + } + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/validator/CipherDataSchemaValidator.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/validator/CipherDataSchemaValidator.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/validator/CipherDataSchemaValidator.java 17 Aug 2012 15:17:20 -0000 1.1 @@ -0,0 +1,48 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption.validator; + +import org.opensaml.xml.encryption.CipherData; +import org.opensaml.xml.validation.ValidationException; +import org.opensaml.xml.validation.Validator; + +/** + * Checks {@link org.opensaml.xml.encryption.CipherData} for Schema compliance. + */ +public class CipherDataSchemaValidator implements Validator { + + /** {@inheritDoc} */ + public void validate(CipherData xmlObject) throws ValidationException { + validateChildrenPresence(xmlObject); + } + + /** + * Validate that required children are present. + * + * @param xmlObject the object to validate + * @throws ValidationException thrown if the object is invalid + */ + protected void validateChildrenPresence(CipherData xmlObject) throws ValidationException { + if (xmlObject.getCipherValue() == null && xmlObject.getCipherReference() == null) { + throw new ValidationException("CipherData did not contain either a CipherValue or CipherReference child"); + } + if (xmlObject.getCipherValue() != null && xmlObject.getCipherReference() != null) { + throw new ValidationException("CipherData contained both a CipherValue and a CipherReference child"); + } + } +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/validator/CipherReferenceSchemaValidator.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/validator/CipherReferenceSchemaValidator.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/validator/CipherReferenceSchemaValidator.java 17 Aug 2012 15:17:20 -0000 1.1 @@ -0,0 +1,47 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption.validator; + +import org.opensaml.xml.encryption.CipherReference; +import org.opensaml.xml.util.DatatypeHelper; +import org.opensaml.xml.validation.ValidationException; +import org.opensaml.xml.validation.Validator; + +/** + * Checks {@link org.opensaml.xml.encryption.CipherReference} for Schema compliance. + */ +public class CipherReferenceSchemaValidator implements Validator { + + /** {@inheritDoc} */ + public void validate(CipherReference xmlObject) throws ValidationException { + validateURI(xmlObject); + } + + /** + * Validate the URI. + * + * @param xmlObject the object to validate + * @throws ValidationException thrown if the object is invalid + */ + protected void validateURI(CipherReference xmlObject) throws ValidationException { + if (DatatypeHelper.isEmpty(xmlObject.getURI())) { + throw new ValidationException("CipherReference URI was empty"); + } + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/validator/EncryptedTypeSchemaValidator.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/validator/EncryptedTypeSchemaValidator.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/validator/EncryptedTypeSchemaValidator.java 17 Aug 2012 15:17:20 -0000 1.1 @@ -0,0 +1,45 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption.validator; + +import org.opensaml.xml.encryption.EncryptedType; +import org.opensaml.xml.validation.ValidationException; +import org.opensaml.xml.validation.Validator; + +/** + * Checks {@link org.opensaml.xml.encryption.EncryptedType} for Schema compliance. + */ +public class EncryptedTypeSchemaValidator implements Validator { + + /** {@inheritDoc} */ + public void validate(EncryptedType xmlObject) throws ValidationException { + validateChildrenPresence(xmlObject); + } + + /** + * Validate that required children are present. + * + * @param xmlObject the object to validate + * @throws ValidationException thrown if the object is invalid + */ + protected void validateChildrenPresence(EncryptedType xmlObject) throws ValidationException { + if (xmlObject.getCipherData() == null) { + throw new ValidationException("EncryptedType did not contain a CipherData child"); + } + } +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/validator/EncryptionMethodSchemaValidator.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/validator/EncryptionMethodSchemaValidator.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/validator/EncryptionMethodSchemaValidator.java 17 Aug 2012 15:17:20 -0000 1.1 @@ -0,0 +1,47 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption.validator; + +import org.opensaml.xml.encryption.EncryptionMethod; +import org.opensaml.xml.util.DatatypeHelper; +import org.opensaml.xml.validation.ValidationException; +import org.opensaml.xml.validation.Validator; + +/** + * Checks {@link org.opensaml.xml.encryption.EncryptionMethod} for Schema compliance. + */ +public class EncryptionMethodSchemaValidator implements Validator { + + /** {@inheritDoc} */ + public void validate(EncryptionMethod xmlObject) throws ValidationException { + validateAlgorithm(xmlObject); + } + + /** + * Validate the algorithm URI. + * + * @param xmlObject the object to validate + * @throws ValidationException thrown if the object is invalid + */ + protected void validateAlgorithm(EncryptionMethod xmlObject) throws ValidationException { + if (DatatypeHelper.isEmpty(xmlObject.getAlgorithm())) { + throw new ValidationException("EncryptionMethod algorithm URI was empty"); + } + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/validator/EncryptionPropertiesSchemaValidator.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/validator/EncryptionPropertiesSchemaValidator.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/validator/EncryptionPropertiesSchemaValidator.java 17 Aug 2012 15:17:20 -0000 1.1 @@ -0,0 +1,46 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption.validator; + +import org.opensaml.xml.encryption.EncryptionProperties; +import org.opensaml.xml.validation.ValidationException; +import org.opensaml.xml.validation.Validator; + +/** + * Checks {@link org.opensaml.xml.encryption.EncryptionProperties} for Schema compliance. + */ +public class EncryptionPropertiesSchemaValidator implements Validator { + + /** {@inheritDoc} */ + public void validate(EncryptionProperties xmlObject) throws ValidationException { + validateTransforms(xmlObject); + } + + /** + * Validate the encryption properties list. + * + * @param xmlObject the object to validate + * @throws ValidationException thrown if the object is invalid + */ + protected void validateTransforms(EncryptionProperties xmlObject) throws ValidationException { + if (xmlObject.getEncryptionProperties().isEmpty()) { + throw new ValidationException("No EncryptionProperty children were present in the EncryptionProperties object"); + } + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/validator/EncryptionPropertySchemaValidator.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/validator/EncryptionPropertySchemaValidator.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/validator/EncryptionPropertySchemaValidator.java 17 Aug 2012 15:17:20 -0000 1.1 @@ -0,0 +1,84 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption.validator; + +import javax.xml.namespace.QName; + +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.encryption.EncryptionProperty; +import org.opensaml.xml.util.XMLConstants; +import org.opensaml.xml.validation.ValidationException; +import org.opensaml.xml.validation.Validator; + +/** + * Checks {@link org.opensaml.xml.encryption.EncryptionProperty} for Schema compliance. + */ +public class EncryptionPropertySchemaValidator implements Validator { + + /** {@inheritDoc} */ + public void validate(EncryptionProperty xmlObject) throws ValidationException { + validateUnknownChildren(xmlObject); + validateChildrenNamespaces(xmlObject); + validateAttributeNamespaces(xmlObject); + } + + /** + * Validate the unknown children. + * + * @param xmlObject the object to validate + * @throws ValidationException thrown if the object is invalid + */ + protected void validateUnknownChildren(EncryptionProperty xmlObject) throws ValidationException { + if (xmlObject.getUnknownXMLObjects().isEmpty()) { + throw new ValidationException("No children were present in the EncryptionProperty object"); + } + } + + /** + * Validate that all children are from another namespace. + * + * @param xmlObject the object to validate + * @throws ValidationException thrown if the object is invalid + */ + protected void validateChildrenNamespaces(EncryptionProperty xmlObject) throws ValidationException { + // Validate that any children are from another namespace. + for (XMLObject child : xmlObject.getUnknownXMLObjects()) { + QName childName = child.getElementQName(); + if (XMLConstants.XMLENC_NS.equals(childName.getNamespaceURI())) { + throw new ValidationException("EncryptionProperty contains an illegal child extension element: " + childName); + } + } + } + + /** + * Validate that any wildcard attributes are from the + * XML namespace http://www.w3.org/XML/1998/namespace. + * + * @param xmlObject the object to validate + * @throws ValidationException thrown if the object is invalid + */ + protected void validateAttributeNamespaces(EncryptionProperty xmlObject) throws ValidationException { + // Validate that any extension attribute are from the XML namespace + for (QName attribName : xmlObject.getUnknownAttributes().keySet()) { + if (! XMLConstants.XML_NS.equals(attribName.getNamespaceURI())) { + throw new ValidationException("EncryptionProperty contains an illegal extension attribute: " + attribName); + } + } + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/validator/KeySizeSchemaValidator.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/validator/KeySizeSchemaValidator.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/validator/KeySizeSchemaValidator.java 17 Aug 2012 15:17:20 -0000 1.1 @@ -0,0 +1,37 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption.validator; + +import org.opensaml.xml.encryption.KeySize; +import org.opensaml.xml.schema.validator.XSIntegerSchemaValidator; + +/** + * Checks {@link org.opensaml.xml.encryption.KeySize} for Schema compliance. + */ +public class KeySizeSchemaValidator extends XSIntegerSchemaValidator { + + /** + * Constructor. + * + */ + public KeySizeSchemaValidator() { + // Don't allow empty content + super(false); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/validator/ReferenceListSchemaValidator.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/validator/ReferenceListSchemaValidator.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/validator/ReferenceListSchemaValidator.java 17 Aug 2012 15:17:20 -0000 1.1 @@ -0,0 +1,46 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption.validator; + +import org.opensaml.xml.encryption.ReferenceList; +import org.opensaml.xml.validation.ValidationException; +import org.opensaml.xml.validation.Validator; + +/** + * Checks {@link org.opensaml.xml.encryption.ReferenceList} for Schema compliance. + */ +public class ReferenceListSchemaValidator implements Validator { + + /** {@inheritDoc} */ + public void validate(ReferenceList xmlObject) throws ValidationException { + validateReferences(xmlObject); + } + + /** + * Validate the list of references. + * + * @param xmlObject the object to validate + * @throws ValidationException thrown if the object is invalid + */ + protected void validateReferences(ReferenceList xmlObject) throws ValidationException { + if (xmlObject.getReferences().isEmpty()) { + throw new ValidationException("No DataReference or KeyReference children were present in the ReferenceList object"); + } + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/validator/ReferenceTypeSchemaValidator.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/validator/ReferenceTypeSchemaValidator.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/validator/ReferenceTypeSchemaValidator.java 17 Aug 2012 15:17:20 -0000 1.1 @@ -0,0 +1,68 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption.validator; + +import javax.xml.namespace.QName; + +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.encryption.ReferenceType; +import org.opensaml.xml.util.DatatypeHelper; +import org.opensaml.xml.util.XMLConstants; +import org.opensaml.xml.validation.ValidationException; +import org.opensaml.xml.validation.Validator; + +/** + * Checks {@link org.opensaml.xml.encryption.ReferenceType} for Schema compliance. + */ +public class ReferenceTypeSchemaValidator implements Validator { + + /** {@inheritDoc} */ + public void validate(ReferenceType xmlObject) throws ValidationException { + validateURI(xmlObject); + validateChildrenNamespaces(xmlObject); + } + + /** + * Validate the URI. + * + * @param xmlObject the object to validate + * @throws ValidationException thrown if the object is invalid + */ + protected void validateURI(ReferenceType xmlObject) throws ValidationException { + if (DatatypeHelper.isEmpty(xmlObject.getURI())) { + throw new ValidationException("ReferenceType URI was empty"); + } + } + + /** + * Validate that all children are from another namespace. + * + * @param xmlObject the object to validate + * @throws ValidationException thrown if the object is invalid + */ + protected void validateChildrenNamespaces(ReferenceType xmlObject) throws ValidationException { + // Validate that any children are from another namespace. + for (XMLObject child : xmlObject.getUnknownXMLObjects()) { + QName childName = child.getElementQName(); + if (XMLConstants.XMLENC_NS.equals(childName.getNamespaceURI())) { + throw new ValidationException("ReferenceType contains an illegal child extension element: " + childName); + } + } + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/validator/TransformsSchemaValidator.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/encryption/validator/TransformsSchemaValidator.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/encryption/validator/TransformsSchemaValidator.java 17 Aug 2012 15:17:20 -0000 1.1 @@ -0,0 +1,46 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.encryption.validator; + +import org.opensaml.xml.encryption.Transforms; +import org.opensaml.xml.validation.ValidationException; +import org.opensaml.xml.validation.Validator; + +/** + * Checks {@link org.opensaml.xml.encryption.Transforms} for Schema compliance. + */ +public class TransformsSchemaValidator implements Validator { + + /** {@inheritDoc} */ + public void validate(Transforms xmlObject) throws ValidationException { + validateTransforms(xmlObject); + } + + /** + * Validate the transforms. + * + * @param xmlObject the object to validate + * @throws ValidationException thrown if the object is invalid + */ + protected void validateTransforms(Transforms xmlObject) throws ValidationException { + if (xmlObject.getTransforms().isEmpty()) { + throw new ValidationException("No Transform children were present in the Transforms object"); + } + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/io/AbstractXMLObjectMarshaller.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/io/AbstractXMLObjectMarshaller.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/io/AbstractXMLObjectMarshaller.java 17 Aug 2012 15:17:18 -0000 1.1 @@ -0,0 +1,464 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.io; + +import java.util.List; +import java.util.Set; + +import javax.xml.namespace.QName; + +import org.opensaml.xml.Configuration; +import org.opensaml.xml.Namespace; +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.parse.XMLParserException; +import org.opensaml.xml.util.DatatypeHelper; +import org.opensaml.xml.util.XMLConstants; +import org.opensaml.xml.util.XMLHelper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +/** + * A thread safe, abstract implementation of the {@link org.opensaml.xml.io.Marshaller} interface. This class handles + * most of the boilerplate code: + *

    + *
  • Ensuring elements to be marshalled are of either the correct xsi:type or element QName
  • + *
  • Setting the appropriate namespace and prefix for the marshalled element
  • + *
  • Setting the xsi:type for the element if the element has an explicit type
  • + *
  • Setting namespaces attributes declared for the element
  • + *
  • Marshalling of child elements
  • + *
+ */ +public abstract class AbstractXMLObjectMarshaller implements Marshaller { + + /** Class logger. */ + private final Logger log = LoggerFactory.getLogger(AbstractXMLObjectMarshaller.class); + + /** The target name and namespace for this marshaller. */ + private QName targetQName; + + /** Factory for XMLObject Marshallers. */ + private MarshallerFactory marshallerFactory; + + /** Constructor. */ + protected AbstractXMLObjectMarshaller() { + marshallerFactory = Configuration.getMarshallerFactory(); + } + + /** + * This constructor supports checking an XMLObject to be marshalled, either element name or schema type, against a + * given namespace/local name pair. + * + * @deprecated no replacement + * + * @param targetNamespaceURI the namespace URI of either the schema type QName or element QName of the elements this + * unmarshaller operates on + * @param targetLocalName the local name of either the schema type QName or element QName of the elements this + * unmarshaller operates on + */ + protected AbstractXMLObjectMarshaller(String targetNamespaceURI, String targetLocalName) { + targetQName = XMLHelper.constructQName(targetNamespaceURI, targetLocalName, null); + + marshallerFactory = Configuration.getMarshallerFactory(); + } + + /** {@inheritDoc} */ + public Element marshall(XMLObject xmlObject) throws MarshallingException { + try { + Document document = Configuration.getParserPool().newDocument(); + return marshall(xmlObject, document); + } catch (XMLParserException e) { + throw new MarshallingException("Unable to create Document to place marshalled elements in", e); + } + } + + /** {@inheritDoc} */ + public Element marshall(XMLObject xmlObject, Document document) throws MarshallingException { + Element domElement; + + log.trace("Starting to marshall {}", xmlObject.getElementQName()); + + if (document == null) { + throw new MarshallingException("Given document may not be null"); + } + + checkXMLObjectIsTarget(xmlObject); + + log.trace("Checking if {} contains a cached DOM representation", xmlObject.getElementQName()); + domElement = xmlObject.getDOM(); + if (domElement != null) { + + prepareForAdoption(xmlObject); + + if (domElement.getOwnerDocument() != document) { + log.trace("Adopting DOM of XMLObject into given Document"); + XMLHelper.adoptElement(domElement, document); + } + + log.trace("Setting DOM of XMLObject as document element of given Document"); + setDocumentElement(document, domElement); + + return domElement; + } + + log.trace("{} does not contain a cached DOM representation. Creating Element to marshall into.", + xmlObject.getElementQName()); + domElement = XMLHelper.constructElement(document, xmlObject.getElementQName()); + + log.trace("Setting created element as document root"); + // we need to do this before the rest of the marshalling so that signing and other ID dependent operations have + // a path to the document root + setDocumentElement(document, domElement); + + domElement = marshallInto(xmlObject, domElement); + + log.trace("Setting created element to DOM cache for XMLObject {}", xmlObject.getElementQName()); + xmlObject.setDOM(domElement); + xmlObject.releaseParentDOM(true); + + return domElement; + } + + /** {@inheritDoc} */ + public Element marshall(XMLObject xmlObject, Element parentElement) throws MarshallingException { + Element domElement; + + log.trace("Starting to marshall {} as child of {}", xmlObject.getElementQName(), + XMLHelper.getNodeQName(parentElement)); + + if (parentElement == null) { + throw new MarshallingException("Given parent element is null"); + } + + checkXMLObjectIsTarget(xmlObject); + + log.trace("Checking if {} contains a cached DOM representation", xmlObject.getElementQName()); + domElement = xmlObject.getDOM(); + if (domElement != null) { + log.trace("{} contains a cached DOM representation", xmlObject.getElementQName()); + + prepareForAdoption(xmlObject); + + log.trace("Appending DOM of XMLObject {} as child of parent element {}", xmlObject.getElementQName(), + XMLHelper.getNodeQName(parentElement)); + XMLHelper.appendChildElement(parentElement, domElement); + + return domElement; + } + + log.trace("{} does not contain a cached DOM representation. Creating Element to marshall into.", + xmlObject.getElementQName()); + Document owningDocument = parentElement.getOwnerDocument(); + domElement = XMLHelper.constructElement(owningDocument, xmlObject.getElementQName()); + + log.trace("Appending newly created element to given parent element"); + // we need to do this before the rest of the marshalling so that signing and other ID dependent operations have + // a path to the document root + XMLHelper.appendChildElement(parentElement, domElement); + domElement = marshallInto(xmlObject, domElement); + + log.trace("Setting created element to DOM cache for XMLObject {}", xmlObject.getElementQName()); + xmlObject.setDOM(domElement); + xmlObject.releaseParentDOM(true); + + return domElement; + + } + + /** + * Sets the given element as the Document Element of the given Document. If the document already has a Document + * Element it is replaced by the given element. + * + * @param document the document + * @param element the Element that will serve as the Document Element + */ + protected void setDocumentElement(Document document, Element element) { + Element documentRoot = document.getDocumentElement(); + if (documentRoot != null) { + document.replaceChild(element, documentRoot); + } else { + document.appendChild(element); + } + } + + /** + * Marshalls the given XMLObject into the given DOM Element. The DOM Element must be within a DOM tree whose root is + * the Document Element of the Document that owns the given DOM Element. + * + * @param xmlObject the XMLObject to marshall + * @param targetElement the Element into which the XMLObject is marshalled into + * + * @return the DOM element the {@link XMLObject} is marshalled into + * + * @throws MarshallingException thrown if there is a problem marshalling the object + */ + protected Element marshallInto(XMLObject xmlObject, Element targetElement) throws MarshallingException { + log.trace("Setting namespace prefix for {} for XMLObject {}", xmlObject.getElementQName().getPrefix(), + xmlObject.getElementQName()); + + marshallNamespacePrefix(xmlObject, targetElement); + + marshallSchemaInstanceAttributes(xmlObject, targetElement); + + marshallNamespaces(xmlObject, targetElement); + + marshallAttributes(xmlObject, targetElement); + + marshallChildElements(xmlObject, targetElement); + + marshallElementContent(xmlObject, targetElement); + + return targetElement; + } + + /** + * Checks to make sure the given XMLObject's schema type or element QName matches the target parameters given at + * marshaller construction time. + * + * @param xmlObject the XMLObject to marshall + * + * @throws MarshallingException thrown if the given object is not or the required type + */ + protected void checkXMLObjectIsTarget(XMLObject xmlObject) throws MarshallingException { + if (targetQName == null) { + log.trace("Targeted QName checking is not available for this marshaller, XMLObject {} was not verified", + xmlObject.getElementQName()); + return; + } + + log.trace("Checking that {} meets target criteria", xmlObject.getElementQName()); + QName type = xmlObject.getSchemaType(); + if (type != null && type.equals(targetQName)) { + log.trace("{} schema type matches target", xmlObject.getElementQName()); + return; + } else { + QName elementQName = xmlObject.getElementQName(); + if (elementQName.equals(targetQName)) { + log.trace("{} element QName matches target", xmlObject.getElementQName()); + return; + } + } + + String errorMsg = + "This marshaller only operations on " + targetQName + " elements not " + xmlObject.getElementQName(); + log.error(errorMsg); + throw new MarshallingException(errorMsg); + } + + /** + * Marshalls the namespace prefix of the XMLObject into the DOM element. + * + * @param xmlObject the XMLObject being marshalled + * @param domElement the DOM element the XMLObject is being marshalled into + */ + protected void marshallNamespacePrefix(XMLObject xmlObject, Element domElement) { + String prefix = xmlObject.getElementQName().getPrefix(); + prefix = DatatypeHelper.safeTrimOrNullString(prefix); + + if (prefix != null) { + domElement.setPrefix(prefix); + } + } + + /** + * Marshalls the child elements of the given XMLObject. + * + * @param xmlObject the XMLObject whose children will be marshalled + * @param domElement the DOM element that will recieved the marshalled children + * + * @throws MarshallingException thrown if there is a problem marshalling a child element + */ + protected void marshallChildElements(XMLObject xmlObject, Element domElement) throws MarshallingException { + log.trace("Marshalling child elements for XMLObject {}", xmlObject.getElementQName()); + + List childXMLObjects = xmlObject.getOrderedChildren(); + if (childXMLObjects != null && childXMLObjects.size() > 0) { + for (XMLObject childXMLObject : childXMLObjects) { + if (childXMLObject == null) { + continue; + } + + log.trace("Getting marshaller for child XMLObject {}", childXMLObject.getElementQName()); + Marshaller marshaller = marshallerFactory.getMarshaller(childXMLObject); + + if (marshaller == null) { + marshaller = marshallerFactory.getMarshaller(Configuration.getDefaultProviderQName()); + + if (marshaller == null) { + String errorMsg = + "No marshaller available for " + childXMLObject.getElementQName() + ", child of " + + xmlObject.getElementQName(); + log.error(errorMsg); + throw new MarshallingException(errorMsg); + } else { + log.trace("No marshaller was registered for {}, child of {}. Using default marshaller", + childXMLObject.getElementQName(), xmlObject.getElementQName()); + } + } + + log.trace("Marshalling {} and adding it to DOM", childXMLObject.getElementQName()); + marshaller.marshall(childXMLObject, domElement); + } + } else { + log.trace("No child elements to marshall for XMLObject {}", xmlObject.getElementQName()); + } + } + + /** + * Creates the xmlns attributes for any namespaces set on the given XMLObject. + * + * @param xmlObject the XMLObject + * @param domElement the DOM element the namespaces will be added to + */ + protected void marshallNamespaces(XMLObject xmlObject, Element domElement) { + log.trace("Marshalling namespace attributes for XMLObject {}", xmlObject.getElementQName()); + Set namespaces = xmlObject.getNamespaces(); + + for (Namespace namespace : namespaces) { + if (!namespace.alwaysDeclare()) { + if (DatatypeHelper.safeEquals(namespace.getNamespacePrefix(), XMLConstants.XML_PREFIX) + || DatatypeHelper.safeEquals(namespace.getNamespaceURI(), XMLConstants.XML_NS)) { + // the "xml" namespace never needs to be declared + continue; + } + + String declared = XMLHelper.lookupNamespaceURI(domElement, namespace.getNamespacePrefix()); + if (declared != null && namespace.getNamespaceURI().equals(declared)) { + log.trace("Namespace {} has already been declared on an ancestor of {} no need to add it here", + namespace, xmlObject.getElementQName()); + continue; + } + } + log.trace("Adding namespace declaration {} to {}", namespace, xmlObject.getElementQName()); + String nsURI = DatatypeHelper.safeTrimOrNullString(namespace.getNamespaceURI()); + String nsPrefix = DatatypeHelper.safeTrimOrNullString(namespace.getNamespacePrefix()); + + XMLHelper.appendNamespaceDeclaration(domElement, nsURI, nsPrefix); + } + } + + /** + * Creates the XSI type, schemaLocation, and noNamespaceSchemaLocation attributes for an XMLObject. + * + * @param xmlObject the XMLObject + * @param domElement the DOM element the namespaces will be added to + * + * @throws MarshallingException thrown if the schema type information is invalid + */ + protected void marshallSchemaInstanceAttributes(XMLObject xmlObject, Element domElement) + throws MarshallingException { + + if (!DatatypeHelper.isEmpty(xmlObject.getSchemaLocation())) { + log.trace("Setting xsi:schemaLocation for XMLObject {} to {}", xmlObject.getElementQName(), + xmlObject.getSchemaLocation()); + domElement.setAttributeNS(XMLConstants.XSI_NS, XMLConstants.XSI_PREFIX + ":schemaLocation", + xmlObject.getSchemaLocation()); + } + + if (!DatatypeHelper.isEmpty(xmlObject.getNoNamespaceSchemaLocation())) { + log.trace("Setting xsi:noNamespaceSchemaLocation for XMLObject {} to {}", xmlObject.getElementQName(), + xmlObject.getNoNamespaceSchemaLocation()); + domElement.setAttributeNS(XMLConstants.XSI_NS, XMLConstants.XSI_PREFIX + ":noNamespaceSchemaLocation", + xmlObject.getNoNamespaceSchemaLocation()); + } + + if (xmlObject.isNilXSBoolean() != null && xmlObject.isNil()) { + log.trace("Setting xsi:nil for XMLObject {} to true", xmlObject.getElementQName()); + domElement.setAttributeNS(XMLConstants.XSI_NS, XMLConstants.XSI_PREFIX + ":nil", xmlObject.isNilXSBoolean() + .toString()); + } + + QName type = xmlObject.getSchemaType(); + if (type == null) { + return; + } + + log.trace("Setting xsi:type attribute with for XMLObject {}", xmlObject.getElementQName()); + String typeLocalName = DatatypeHelper.safeTrimOrNullString(type.getLocalPart()); + String typePrefix = DatatypeHelper.safeTrimOrNullString(type.getPrefix()); + + if (typeLocalName == null) { + throw new MarshallingException("The type QName on XMLObject " + xmlObject.getElementQName() + + " may not have a null local name"); + } + + if (type.getNamespaceURI() == null) { + throw new MarshallingException("The type URI QName on XMLObject " + xmlObject.getElementQName() + + " may not have a null namespace URI"); + } + + String attributeValue; + if (typePrefix == null) { + attributeValue = typeLocalName; + } else { + attributeValue = typePrefix + ":" + typeLocalName; + } + + domElement.setAttributeNS(XMLConstants.XSI_NS, XMLConstants.XSI_PREFIX + ":type", attributeValue); + } + + /** + * Marshalls a given XMLObject into a W3C Element. The given signing context should be blindly passed to the + * marshaller for child elements. The XMLObject passed to this method is guaranteed to be of the target name + * specified during this unmarshaller's construction. + * + * @param xmlObject the XMLObject to marshall + * @param domElement the W3C DOM element + * + * @throws MarshallingException thrown if there is a problem marshalling the element + */ + protected abstract void marshallAttributes(XMLObject xmlObject, Element domElement) throws MarshallingException; + + /** + * Marshalls data from the XMLObject into content of the DOM Element. + * + * @param xmlObject the XMLObject + * @param domElement the DOM element recieving the content + * + * @throws MarshallingException thrown if the textual content can not be added to the DOM element + */ + protected abstract void marshallElementContent(XMLObject xmlObject, Element domElement) throws MarshallingException; + + /** + * Prepares the given DOM caching XMLObject for adoption into another document. If the XMLObject has a parent then + * all visible namespaces used by the given XMLObject and its descendants are declared within that subtree and the + * parent's DOM is invalidated. + * + * @param domCachingObject the XMLObject to prepare for adoption + * + * @throws MarshallingException thrown if a namespace within the XMLObject's DOM subtree can not be resolved. + */ + private void prepareForAdoption(XMLObject domCachingObject) throws MarshallingException { + if (domCachingObject.getParent() != null) { + log.trace("Rooting all visible namespaces of XMLObject {} before adding it to new parent Element", + domCachingObject.getElementQName()); + try { + XMLHelper.rootNamespaces(domCachingObject.getDOM()); + } catch (XMLParserException e) { + String errorMsg = + "Unable to root namespaces of cached DOM element, " + domCachingObject.getElementQName(); + log.error(errorMsg, e); + throw new MarshallingException(errorMsg, e); + } + + log.trace("Release DOM of XMLObject parent"); + domCachingObject.releaseParentDOM(true); + } + } +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/io/AbstractXMLObjectUnmarshaller.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/io/AbstractXMLObjectUnmarshaller.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/io/AbstractXMLObjectUnmarshaller.java 17 Aug 2012 15:17:18 -0000 1.1 @@ -0,0 +1,383 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.io; + +import javax.xml.namespace.QName; + +import org.opensaml.xml.Configuration; +import org.opensaml.xml.Namespace; +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.XMLObjectBuilder; +import org.opensaml.xml.XMLObjectBuilderFactory; +import org.opensaml.xml.schema.XSBooleanValue; +import org.opensaml.xml.util.DatatypeHelper; +import org.opensaml.xml.util.XMLConstants; +import org.opensaml.xml.util.XMLHelper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.w3c.dom.Attr; +import org.w3c.dom.Element; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.w3c.dom.Text; + +/** + * An thread safe abstract unmarshaller. This unmarshaller will: + *
    + *
  • Unmarshalling namespace decleration attributes
  • + *
  • Unmarshalling schema instance type (xsi:type) decleration attributes
  • + *
  • Delegating to child classes element, text, and attribute processing
  • + *
+ * + * NOTE: In the case of Text nodes this unmarshaller will use {@link org.w3c.dom.Text#getWholeText()} + * to retrieve the textual content. This is probably exceptable in almost all cases, if, however, you need to deal with + * elements that contain multiple text node children you will need to override + * {@link #unmarshallTextContent(XMLObject, Text)} and do "the right thing" for your implementation. + */ +public abstract class AbstractXMLObjectUnmarshaller implements Unmarshaller { + + /** Class logger. */ + private final Logger log = LoggerFactory.getLogger(AbstractXMLObjectUnmarshaller.class); + + /** The target name and namespace for this unmarshaller. */ + private QName targetQName; + + /** Factory for XMLObjectBuilders. */ + private XMLObjectBuilderFactory xmlObjectBuilderFactory; + + /** Factory for creating unmarshallers for child elements. */ + private UnmarshallerFactory unmarshallerFactory; + + /** + * Constructor. + */ + protected AbstractXMLObjectUnmarshaller() { + xmlObjectBuilderFactory = Configuration.getBuilderFactory(); + unmarshallerFactory = Configuration.getUnmarshallerFactory(); + } + + /** + * This constructor supports checking a DOM Element to be unmarshalled, either element name or schema type, against + * a given namespace/local name pair. + * + * @deprecated no replacement + * + * @param targetNamespaceURI the namespace URI of either the schema type QName or element QName of the elements this + * unmarshaller operates on + * @param targetLocalName the local name of either the schema type QName or element QName of the elements this + * unmarshaller operates on + */ + protected AbstractXMLObjectUnmarshaller(String targetNamespaceURI, String targetLocalName) { + targetQName = XMLHelper.constructQName(targetNamespaceURI, targetLocalName, null); + + xmlObjectBuilderFactory = Configuration.getBuilderFactory(); + unmarshallerFactory = Configuration.getUnmarshallerFactory(); + } + + /** {@inheritDoc} */ + public XMLObject unmarshall(Element domElement) throws UnmarshallingException { + log.trace("Starting to unmarshall DOM element {}", XMLHelper.getNodeQName(domElement)); + + checkElementIsTarget(domElement); + + XMLObject xmlObject = buildXMLObject(domElement); + + log.trace("Unmarshalling attributes of DOM Element {}", XMLHelper.getNodeQName(domElement)); + NamedNodeMap attributes = domElement.getAttributes(); + Node attribute; + for (int i = 0; i < attributes.getLength(); i++) { + attribute = attributes.item(i); + + // These should allows be attribute nodes, but just in case... + if (attribute.getNodeType() == Node.ATTRIBUTE_NODE) { + unmarshallAttribute(xmlObject, (Attr) attribute); + } + } + + log.trace("Unmarshalling other child nodes of DOM Element {}", XMLHelper.getNodeQName(domElement)); + NodeList childNodes = domElement.getChildNodes(); + Node childNode; + for (int i = 0; i < childNodes.getLength(); i++) { + childNode = childNodes.item(i); + + if (childNode.getNodeType() == Node.ATTRIBUTE_NODE) { + unmarshallAttribute(xmlObject, (Attr) childNode); + } else if (childNode.getNodeType() == Node.ELEMENT_NODE) { + unmarshallChildElement(xmlObject, (Element) childNode); + } else if (childNode.getNodeType() == Node.TEXT_NODE) { + unmarshallTextContent(xmlObject, (Text) childNode); + } + } + + xmlObject.setDOM(domElement); + return xmlObject; + } + + /** + * Checks that the given DOM Element's XSI type or namespace qualified element name matches the target QName of this + * unmarshaller. + * + * @param domElement the DOM element to check + * + * @throws UnmarshallingException thrown if the DOM Element does not match the target of this unmarshaller + */ + protected void checkElementIsTarget(Element domElement) throws UnmarshallingException { + QName elementName = XMLHelper.getNodeQName(domElement); + + if (targetQName == null) { + log.trace( + "Targeted QName checking is not available for this unmarshaller, DOM Element {} was not verified", + elementName); + return; + } + + log.trace("Checking that {} meets target criteria.", elementName); + + QName type = XMLHelper.getXSIType(domElement); + + if (type != null && type.equals(targetQName)) { + log.trace("{} schema type matches target.", elementName); + return; + } else { + if (elementName.equals(targetQName)) { + log.trace("{} element name matches target.", elementName); + return; + } else { + String errorMsg = "This unmarshaller only operates on " + targetQName + " elements not " + elementName; + log.error(errorMsg); + throw new UnmarshallingException(errorMsg); + } + } + } + + /** + * Constructs the XMLObject that the given DOM Element will be unmarshalled into. If the DOM element has an XML + * Schema type defined this method will attempt to retrieve an XMLObjectBuilder, from the factory given at + * construction time, using the schema type. If no schema type is present or no builder is registered with the + * factory for the schema type, the elements QName is used. Once the builder is found the XMLObject is create by + * invoking {@link XMLObjectBuilder#buildObject(String, String, String)}. Extending classes may wish to override + * this logic if more than just schema type or element name (e.g. element attributes or content) need to be used to + * determine which XMLObjectBuilder should be used to create the XMLObject. + * + * @param domElement the DOM Element the created XMLObject will represent + * + * @return the empty XMLObject that DOM Element can be unmarshalled into + * + * @throws UnmarshallingException thrown if there is now XMLObjectBuilder registered for the given DOM Element + */ + protected XMLObject buildXMLObject(Element domElement) throws UnmarshallingException { + log.trace("Building XMLObject for {}", XMLHelper.getNodeQName(domElement)); + XMLObjectBuilder xmlObjectBuilder; + + xmlObjectBuilder = xmlObjectBuilderFactory.getBuilder(domElement); + if (xmlObjectBuilder == null) { + xmlObjectBuilder = xmlObjectBuilderFactory.getBuilder(Configuration.getDefaultProviderQName()); + if (xmlObjectBuilder == null) { + String errorMsg = "Unable to located builder for " + XMLHelper.getNodeQName(domElement); + log.error(errorMsg); + throw new UnmarshallingException(errorMsg); + } else { + log.trace("No builder was registered for {} but the default builder {} was available, using it.", + XMLHelper.getNodeQName(domElement), xmlObjectBuilder.getClass().getName()); + } + } + + return xmlObjectBuilder.buildObject(domElement); + } + + /** + * Unmarshalls the attributes from the given DOM Attr into the given XMLObject. If the attribute is an XML namespace + * declaration the attribute is passed to + * {@link AbstractXMLObjectUnmarshaller#unmarshallNamespaceAttribute(XMLObject, Attr)}. If it is an schema type + * decleration (xsi:type) it is ignored because this attribute is handled by {@link #buildXMLObject(Element)}. All + * other attributes are passed to the {@link #processAttribute(XMLObject, Attr)} + * + * @param attribute the attribute to be unmarshalled + * @param xmlObject the XMLObject that will recieve information from the DOM attribute + * + * @throws UnmarshallingException thrown if there is a problem unmarshalling an attribute + */ + protected void unmarshallAttribute(XMLObject xmlObject, Attr attribute) throws UnmarshallingException { + QName attribName = XMLHelper.getNodeQName(attribute); + log.trace("Pre-processing attribute {}", attribName); + String attributeNamespace = DatatypeHelper.safeTrimOrNullString(attribute.getNamespaceURI()); + + if (DatatypeHelper.safeEquals(attributeNamespace, XMLConstants.XMLNS_NS)) { + unmarshallNamespaceAttribute(xmlObject, attribute); + } else if (DatatypeHelper.safeEquals(attributeNamespace, XMLConstants.XSI_NS)) { + unmarshallSchemaInstanceAttributes(xmlObject, attribute); + } else { + log.trace("Attribute {} is neither a schema type nor namespace, calling processAttribute()", XMLHelper + .getNodeQName(attribute)); + String attributeNSURI = attribute.getNamespaceURI(); + String attributeNSPrefix; + if (attributeNSURI != null) { + attributeNSPrefix = attribute.lookupPrefix(attributeNSURI); + if (attributeNSPrefix == null && XMLConstants.XML_NS.equals(attributeNSURI)) { + attributeNSPrefix = XMLConstants.XML_PREFIX; + } + xmlObject.getNamespaceManager().registerAttributeName(attribName); + } + + checkIDAttribute(attribute); + + processAttribute(xmlObject, attribute); + } + } + + /** + * Unmarshalls a namespace declaration attribute. + * + * @param xmlObject the xmlObject to recieve the namespace decleration + * @param attribute the namespace decleration attribute + */ + protected void unmarshallNamespaceAttribute(XMLObject xmlObject, Attr attribute) { + log.trace("{} is a namespace declaration, adding it to the list of namespaces on the XMLObject", XMLHelper + .getNodeQName(attribute)); + Namespace namespace; + if(DatatypeHelper.safeEquals(attribute.getLocalName(), XMLConstants.XMLNS_PREFIX)){ + namespace = new Namespace(attribute.getValue(), null); + }else{ + namespace = new Namespace(attribute.getValue(), attribute.getLocalName()); + } + namespace.setAlwaysDeclare(true); + xmlObject.getNamespaceManager().registerNamespaceDeclaration(namespace); + } + + /** + * Unmarshalls the XSI type, schemaLocation, and noNamespaceSchemaLocation attributes. + * + * @param xmlObject the xmlObject to recieve the namespace decleration + * @param attribute the namespace decleration attribute + */ + protected void unmarshallSchemaInstanceAttributes(XMLObject xmlObject, Attr attribute) { + QName attribName = XMLHelper.getNodeQName(attribute); + if (XMLConstants.XSI_TYPE_ATTRIB_NAME.equals(attribName)) { + log.trace("Saw XMLObject {} with an xsi:type of: {}", xmlObject.getElementQName(), attribute.getValue()); + } else if (XMLConstants.XSI_SCHEMA_LOCATION_ATTRIB_NAME.equals(attribName)) { + log.trace("Saw XMLObject {} with an xsi:schemaLocation of: {}", xmlObject.getElementQName(), + attribute.getValue()); + xmlObject.setSchemaLocation(attribute.getValue()); + } else if (XMLConstants.XSI_NO_NAMESPACE_SCHEMA_LOCATION_ATTRIB_NAME.equals(attribName)) { + log.trace("Saw XMLObject {} with an xsi:noNamespaceSchemaLocation of: {}", xmlObject.getElementQName(), + attribute.getValue()); + xmlObject.setNoNamespaceSchemaLocation(attribute.getValue()); + } else if (XMLConstants.XSI_NIL_ATTRIB_NAME.equals(attribName)) { + log.trace("Saw XMLObject {} with an xsi:nil of: {}", xmlObject.getElementQName(), + attribute.getValue()); + xmlObject.setNil(XSBooleanValue.valueOf(attribute.getValue())); + } + } + + /** + * Check whether the attribute's QName is registered in the global ID attribute registry. If it is, and the + * specified attribute's DOM Level 3 Attr.isId() is false (due to lack of schema validation, for example), then + * declare the attribute as an ID type in the DOM on the attribute's owning element. This is to handle cases where + * the underlying DOM needs to accurately reflect an attribute's ID-ness, for example ID reference resolution within + * the Apache XML Security library. + * + * @param attribute the DOM attribute to be checked + */ + protected void checkIDAttribute(Attr attribute) { + QName attribName = XMLHelper.getNodeQName(attribute); + if (Configuration.isIDAttribute(attribName) && !attribute.isId()) { + attribute.getOwnerElement().setIdAttributeNode(attribute, true); + } + } + + /** + * Unmarshalls given Element's children. For each child an unmarshaller is retrieved using + * {@link UnmarshallerFactory#getUnmarshaller(Element)}. The unmarshaller is then used to unmarshall the child + * element and the resultant XMLObject is passed to {@link #processChildElement(XMLObject, XMLObject)} for further + * processing. + * + * @param xmlObject the parent object of the unmarshalled children + * @param childElement the child element to be unmarshalled + * + * @throws UnmarshallingException thrown if an error occurs unmarshalling the chilren elements + */ + protected void unmarshallChildElement(XMLObject xmlObject, Element childElement) throws UnmarshallingException { + log.trace("Unmarshalling child elements of XMLObject {}", xmlObject.getElementQName()); + + Unmarshaller unmarshaller = unmarshallerFactory.getUnmarshaller(childElement); + + if (unmarshaller == null) { + unmarshaller = unmarshallerFactory.getUnmarshaller(Configuration.getDefaultProviderQName()); + if (unmarshaller == null) { + String errorMsg = "No unmarshaller available for " + XMLHelper.getNodeQName(childElement) + + ", child of " + xmlObject.getElementQName(); + log.error(errorMsg); + throw new UnmarshallingException(errorMsg); + } else { + log.trace("No unmarshaller was registered for {}, child of {}. Using default unmarshaller.", XMLHelper + .getNodeQName(childElement), xmlObject.getElementQName()); + } + } + + log.trace("Unmarshalling child element {}with unmarshaller {}", XMLHelper.getNodeQName(childElement), + unmarshaller.getClass().getName()); + processChildElement(xmlObject, unmarshaller.unmarshall(childElement)); + } + + /** + * Unmarshalls the given Text node into a usable string by way of {@link Text#getWholeText()} and passes it off to + * {@link AbstractXMLObjectUnmarshaller#processElementContent(XMLObject, String)} if the string is not null and + * contains something other than whitespace. + * + * @param xmlObject the XMLObject recieving the element content + * @param content the textual content + * + * @throws UnmarshallingException thrown if there is a problem unmarshalling the text node + */ + protected void unmarshallTextContent(XMLObject xmlObject, Text content) throws UnmarshallingException { + String textContent = DatatypeHelper.safeTrimOrNullString(content.getWholeText()); + if (textContent != null) { + processElementContent(xmlObject, textContent); + } + } + + /** + * Called after a child element has been unmarshalled so that it can be added to the parent XMLObject. + * + * @param parentXMLObject the parent XMLObject + * @param childXMLObject the child XMLObject + * + * @throws UnmarshallingException thrown if there is a problem adding the child to the parent + */ + protected abstract void processChildElement(XMLObject parentXMLObject, XMLObject childXMLObject) + throws UnmarshallingException; + + /** + * Called after an attribute has been unmarshalled so that it can be added to the XMLObject. + * + * @param xmlObject the XMLObject + * @param attribute the attribute + * + * @throws UnmarshallingException thrown if there is a problem adding the attribute to the XMLObject + */ + protected abstract void processAttribute(XMLObject xmlObject, Attr attribute) throws UnmarshallingException; + + /** + * Called if the element being unmarshalled contained textual content so that it can be added to the XMLObject. + * + * @param xmlObject XMLObject the content will be given to + * @param elementContent the Element's content + */ + protected abstract void processElementContent(XMLObject xmlObject, String elementContent); +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/io/BaseXMLObjectMarshaller.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/io/BaseXMLObjectMarshaller.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/io/BaseXMLObjectMarshaller.java 17 Aug 2012 15:17:18 -0000 1.1 @@ -0,0 +1,41 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.io; + +import org.opensaml.xml.XMLObject; +import org.w3c.dom.Element; + +/** + * Base class for {@link Marshaller} classes. + * + * This base class provides no-op implementations of the methods {@link #marshallAttributes(XMLObject, Element)} and + * {@link #marshallElementContent(XMLObject, Element)}. Developers extending this class may need to override one or + * both of these. + */ +public abstract class BaseXMLObjectMarshaller extends AbstractXMLObjectMarshaller { + + /** {@inheritDoc} */ + protected void marshallAttributes(XMLObject xmlObject, Element domElement) throws MarshallingException { + + } + + /** {@inheritDoc} */ + protected void marshallElementContent(XMLObject xmlObject, Element domElement) throws MarshallingException { + + } +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/io/BaseXMLObjectUnmarshaller.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/io/BaseXMLObjectUnmarshaller.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/io/BaseXMLObjectUnmarshaller.java 17 Aug 2012 15:17:18 -0000 1.1 @@ -0,0 +1,47 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.io; + +import org.opensaml.xml.XMLObject; +import org.w3c.dom.Attr; + +/** + * Base class for {@link Unmarshaller} classes. + * + * This base class provides no-op implementations of the methods {@link #processAttribute(XMLObject, Attr)}, + * {@link #processChildElement(XMLObject, XMLObject)}, and {@link #processElementContent(XMLObject, String)}. + * Developers extending this class may need to override one or both of these. + */ +public abstract class BaseXMLObjectUnmarshaller extends AbstractXMLObjectUnmarshaller { + + /** {@inheritDoc} */ + protected void processAttribute(XMLObject xmlObject, Attr attribute) throws UnmarshallingException { + + } + + /** {@inheritDoc} */ + protected void processChildElement(XMLObject parentXMLObject, XMLObject childXMLObject) + throws UnmarshallingException { + + } + + /** {@inheritDoc} */ + protected void processElementContent(XMLObject xmlObject, String elementContent) { + + } +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/io/Marshaller.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/io/Marshaller.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/io/Marshaller.java 17 Aug 2012 15:17:18 -0000 1.1 @@ -0,0 +1,69 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.io; + +import org.opensaml.xml.XMLObject; +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +/** + * Marshallers are used to marshall a {@link org.opensaml.xml.XMLObject} into a W3C DOM element. + */ +public interface Marshaller { + + /** + * Marshall this element, and its children, and root them in a newly created Document. The Document is created by a + * {@link javax.xml.parsers.DocumentBuilder} obtained from a {@link javax.xml.parsers.DocumentBuilderFactory} + * created without any additional parameters or properties set; that is the system defaults properties are used. + * + * @param xmlObject the object to marshall + * + * @return the W3C DOM element representing this SAML element + * + * @throws MarshallingException thrown if there is a problem marshalling the given object + */ + public Element marshall(XMLObject xmlObject) throws MarshallingException; + + /** + * Marshall this element, and its children, into a W3C DOM element. If the document does not have a Document Element + * the Element resulting from this marshalling will be set as the Document Element. + * + * @param xmlObject the object to marshall + * @param document the DOM document the marshalled element will be placed in + * + * @return the W3C DOM element representing this XMLObject + * + * @throws MarshallingException thrown if there is a problem marshalling the given object + */ + public Element marshall(XMLObject xmlObject, Document document) throws MarshallingException; + + /** + * Marshall the given XMLObject and append it as a child to the given parent element. + * + * NOTE: The given Element must be within a DOM tree whose root is the root of the Document owning + * the given Element. + * + * @param xmlObject the XMLObject to be marshalled + * @param parentElement the parent of the Element resulting from marshalling the given XMLObject + * + * @return the marshalled XMLObject + * + * @throws MarshallingException thrown if the given XMLObject can not be marshalled. + */ + public Element marshall(XMLObject xmlObject, Element parentElement) throws MarshallingException; +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/io/MarshallerFactory.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/io/MarshallerFactory.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/io/MarshallerFactory.java 17 Aug 2012 15:17:18 -0000 1.1 @@ -0,0 +1,125 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.io; + +import java.util.Collections; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import javax.xml.namespace.QName; + +import org.opensaml.xml.XMLObject; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * This thread-safe factory creates {@link org.opensaml.xml.io.Marshaller}s that can be used to convert + * {@link org.opensaml.xml.XMLObject}s into W3C DOM elements. Marshallers are stored and retrieved by a + * {@link javax.xml.namespace.QName} key. This key is either the XML Schema Type or element QName of the XML element the + * XMLObject is marshalled into. + */ +public class MarshallerFactory { + + /** Class logger. */ + private final Logger log = LoggerFactory.getLogger(MarshallerFactory.class); + + /** Map of marshallers to the elements they are for. */ + private Map marshallers; + + /** + * Constructor. + */ + public MarshallerFactory() { + marshallers = new ConcurrentHashMap(); + } + + /** + * Gets the Marshaller for a particular element or null if no marshaller is registered for an element. + * + * @param key the key the marshaller was registered under + * + * @return the Marshaller or null + */ + public Marshaller getMarshaller(QName key) { + if (key == null) { + return null; + } + + return marshallers.get(key); + } + + /** + * Retrieves the marshaller for the given XMLObject. The schema type, if present, is tried first as the key with the + * element QName used if no schema type is present or does not have a marshaller registered under it. + * + * @param xmlObject the XMLObject to retrieve the marshaller for + * + * @return the marshaller that can be used for the given XMLObject + */ + public Marshaller getMarshaller(XMLObject xmlObject) { + Marshaller marshaller; + + marshaller = getMarshaller(xmlObject.getSchemaType()); + + if (marshaller == null) { + marshaller = getMarshaller(xmlObject.getElementQName()); + } + + return marshaller; + } + + /** + * Gets an immutable listing of all the Marshallers currently registered. + * + * @return a listing of all the Marshallers currently registered + */ + public Map getMarshallers() { + return Collections.unmodifiableMap(marshallers); + } + + /** + * Registers a Marshaller with this factory. If a Marshaller exist for the element name given it is replaced with + * the given marshaller. + * + * @param key the key the marshaller was registered under + * @param marshaller the Marshaller + */ + public void registerMarshaller(QName key, Marshaller marshaller) { + log.debug("Registering marshaller, {}, for object type {}", marshaller.getClass().getName(), key); + if(key == null){ + throw new IllegalArgumentException("Marshaller key may not be null"); + } + marshallers.put(key, marshaller); + } + + /** + * Deregisters the marshaller for the given element. + * + * @param key the key the marshaller was registered under + * + * @return the Marshaller previously registered or null + */ + public Marshaller deregisterMarshaller(QName key) { + log.debug("Deregistering marshaller for object type {}", key); + if(key != null){ + return marshallers.remove(key); + } + + return null; + } +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/io/MarshallingException.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/io/MarshallingException.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/io/MarshallingException.java 17 Aug 2012 15:17:18 -0000 1.1 @@ -0,0 +1,62 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.io; + +/** + * Exception thrown when error occurs marshalling an XMLObject to a DOM Element. + */ +public class MarshallingException extends Exception { + + /** Serial version UID. */ + private static final long serialVersionUID = 7381813529926476459L; + + /** + * Constructor. + */ + public MarshallingException() { + super(); + } + + /** + * Constructor. + * + * @param message exception message + */ + public MarshallingException(String message) { + super(message); + } + + /** + * Constructor. + * + * @param wrappedException exception to be wrapped by this one + */ + public MarshallingException(Exception wrappedException) { + super(wrappedException); + } + + /** + * Constructor. + * + * @param message exception message + * @param wrappedException exception to be wrapped by this one + */ + public MarshallingException(String message, Exception wrappedException) { + super(message, wrappedException); + } +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/io/Unmarshaller.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/io/Unmarshaller.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/io/Unmarshaller.java 17 Aug 2012 15:17:18 -0000 1.1 @@ -0,0 +1,38 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.io; + +import org.opensaml.xml.XMLObject; +import org.w3c.dom.Element; + +/** + * Unmarshallers are used to unmarshall a W3C DOM element into a {@link org.opensaml.xml.XMLObject}. + */ +public interface Unmarshaller { + + /** + * Unmarshalls the given W3C DOM element into a XMLObject. + * + * @param element the DOM Element + * + * @return the unmarshalled XMLObject + * + * @throws UnmarshallingException thrown if an error occurs unmarshalling the DOM element into the XMLObject + */ + public XMLObject unmarshall(Element element) throws UnmarshallingException; +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/io/UnmarshallerFactory.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/io/UnmarshallerFactory.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/io/UnmarshallerFactory.java 17 Aug 2012 15:17:18 -0000 1.1 @@ -0,0 +1,126 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.io; + +import java.util.Collections; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import javax.xml.namespace.QName; + +import org.opensaml.xml.util.XMLHelper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.w3c.dom.Element; + +/** + * This thread-safe factory creates {@link org.opensaml.xml.io.Unmarshaller}s that can be used to convert W3C DOM + * elements into {@link org.opensaml.xml.XMLObject}s. Unmarshallers are stored and retrieved by a + * {@link javax.xml.namespace.QName} key. This key is either the XML Schema Type or element QName of the XML element + * being unmarshalled. + */ +public class UnmarshallerFactory { + + /** Class logger. */ + private final Logger log = LoggerFactory.getLogger(UnmarshallerFactory.class); + + /** Map of unmarshallers to the elements they are for. */ + private Map unmarshallers; + + /** + * Constructor. + */ + public UnmarshallerFactory() { + unmarshallers = new ConcurrentHashMap(); + } + + /** + * Gets the Unmarshaller for a particular element or null if no unmarshaller is registered for an element. + * + * @param key the key the unmarshaller was registered under + * + * @return the Unmarshaller + */ + public Unmarshaller getUnmarshaller(QName key) { + if (key == null) { + return null; + } + + return unmarshallers.get(key); + } + + /** + * Retrieves the unmarshaller for the given element. The schema type, if present, is tried first as the key with the + * element QName used if no schema type is present or does not have a unmarshaller registered under it. + * + * @param domElement the element to retrieve the unmarshaller for + * + * @return the unmarshaller for the XMLObject the given element can be unmarshalled into + */ + public Unmarshaller getUnmarshaller(Element domElement) { + Unmarshaller unmarshaller; + + unmarshaller = getUnmarshaller(XMLHelper.getXSIType(domElement)); + + if (unmarshaller == null) { + unmarshaller = getUnmarshaller(XMLHelper.getNodeQName(domElement)); + } + + return unmarshaller; + } + + /** + * Gets an immutable listing of all the Unarshallers currently registered. + * + * @return a listing of all the Unmarshallers currently registered + */ + public Map getUnmarshallers() { + return Collections.unmodifiableMap(unmarshallers); + } + + /** + * Registers an Unmarshaller with this factory. If an Unmarshaller exist for the Qname given it is replaced with the + * given unmarshaller. + * + * @param key the key the unmarshaller was registered under + * @param unmarshaller the Unmarshaller + */ + public void registerUnmarshaller(QName key, Unmarshaller unmarshaller) { + log.debug("Registering unmarshaller, {}, for object type, {}", unmarshaller.getClass().getName(), key); + if (key == null) { + throw new IllegalArgumentException("Unmarshaller key may not be null"); + } + unmarshallers.put(key, unmarshaller); + } + + /** + * Deregisters the unmarshaller for the given element. + * + * @param key the key the unmarshaller was registered under + * + * @return the Unmarshaller previously registered or null + */ + public Unmarshaller deregisterUnmarshaller(QName key) { + log.debug("Deregistering marshaller for object type {}", key); + if (key != null) { + return unmarshallers.remove(key); + } + + return null; + } +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/io/UnmarshallingException.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/io/UnmarshallingException.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/io/UnmarshallingException.java 17 Aug 2012 15:17:18 -0000 1.1 @@ -0,0 +1,64 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.io; + +/** + * Exception thrown when error occurs unmarshalling a DOM Element to a XMLObject. + */ +public class UnmarshallingException extends Exception { + + /** + * Serial version UID. + */ + private static final long serialVersionUID = 7512624219806550152L; + + /** + * Constructor. + */ + public UnmarshallingException() { + super(); + } + + /** + * Constructor. + * + * @param message exception message + */ + public UnmarshallingException(String message) { + super(message); + } + + /** + * Constructor. + * + * @param wrappedException exception to be wrapped by this one + */ + public UnmarshallingException(Exception wrappedException) { + super(wrappedException); + } + + /** + * Constructor. + * + * @param message exception message + * @param wrappedException exception to be wrapped by this one + */ + public UnmarshallingException(String message, Exception wrappedException) { + super(message, wrappedException); + } +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/io/package.html =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/io/package.html,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/io/package.html 17 Aug 2012 15:17:18 -0000 1.1 @@ -0,0 +1,6 @@ + + +Interfaces and abstract implementations of marshallers and unmarshallers. + + + \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/parse/BasicParserPool.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/parse/BasicParserPool.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/parse/BasicParserPool.java 17 Aug 2012 15:17:19 -0000 1.1 @@ -0,0 +1,768 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.parse; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.Reader; +import java.lang.ref.SoftReference; +import java.util.Collections; +import java.util.Map; +import java.util.Stack; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.validation.Schema; + +import org.opensaml.xml.Configuration; +import org.opensaml.xml.util.LazyMap; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.w3c.dom.DOMImplementation; +import org.w3c.dom.Document; +import org.xml.sax.EntityResolver; +import org.xml.sax.ErrorHandler; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; + +/** + * A pool of JAXP 1.3 {@link DocumentBuilder}s. + * + *

This implementation of {@link ParserPool} allows its properties to be modified over + * time and versions the builders it manages appropriately. There are certain performance penalties + * for doing this. For a more performant implementation that does not support versioning or property + * modification over time, see {@link StaticBasicParserPool}.

+ * + *

This is a pool implementation of the caching factory variety, and as such imposes no upper bound + * on the number of DocumentBuilders allowed to be concurrently checked out and in use. It does however + * impose a limit on the size of the internal cache of idle builder instances via the value configured + * via {@link #setMaxPoolSize(int)}.

+ * + *

Builders retrieved from this pool may (but are not required to) be returned to the pool with the method + * {@link #returnBuilder(DocumentBuilder)}. Builders checked out prior to a change in the pool's properties will not be + * effected by the change and will be appropriately dealt with when they are returned.

+ * + *

References to builders are kept by way of {@link SoftReference} so that the garbage collector + * may reap the builders if the system is running out of memory.

+ */ +public class BasicParserPool implements ParserPool { + + /** Class logger. */ + private final Logger log = LoggerFactory.getLogger(BasicParserPool.class); + + /** Current version of the pool. */ + private long poolVersion; + + /** Whether a change has been made to the builder configuration but has not yet been applied. */ + private boolean dirtyBuilderConfiguration; + + /** Factory used to create new builders. */ + private DocumentBuilderFactory builderFactory; + + /** Cache of document builders. */ + private Stack> builderPool; + + /** Max number of builders allowed in the pool. Default value: 5 */ + private int maxPoolSize; + + /** Builder attributes. */ + private Map builderAttributes; + + /** Whether the builders are coalescing. Default value: true */ + private boolean coalescing; + + /** Whether the builders expand entity references. Default value: true */ + private boolean expandEntityReferences; + + /** Builder features. */ + private Map builderFeatures; + + /** Whether the builders ignore comments. Default value: true */ + private boolean ignoreComments; + + /** Whether the builders ignore element content whitespace. Default value: true */ + private boolean ignoreElementContentWhitespace; + + /** Whether the builders are namespace aware. Default value: true */ + private boolean namespaceAware; + + /** Schema used to validate parsed content. */ + private Schema schema; + + /** Whether the builder should validate. Default value: false */ + private boolean dtdValidating; + + /** Whether the builders are XInclude aware. Default value: false */ + private boolean xincludeAware; + + /** Entity resolver used by builders. */ + private EntityResolver entityResolver; + + /** Error handler used by builders. */ + private ErrorHandler errorHandler; + + /** Constructor. */ + public BasicParserPool() { + maxPoolSize = 5; + builderPool = new Stack>(); + builderAttributes = new LazyMap(); + coalescing = true; + expandEntityReferences = true; + builderFeatures = new LazyMap(); + ignoreComments = true; + ignoreElementContentWhitespace = true; + namespaceAware = true; + schema = null; + dtdValidating = false; + xincludeAware = false; + errorHandler = new LoggingErrorHandler(log); + + try { + dirtyBuilderConfiguration = true; + initializePool(); + } catch (XMLParserException e) { + // default settings, no parsing exception + } + } + + /** {@inheritDoc} */ + public DocumentBuilder getBuilder() throws XMLParserException { + DocumentBuilder builder = null; + long version = 0; + + if (dirtyBuilderConfiguration) { + initializePool(); + } + + synchronized(this) { + version = getPoolVersion(); + if (!builderPool.isEmpty()) { + builder = builderPool.pop().get(); + } + // Will be null if either the stack was empty, or the SoftReference + // has been garbage-collected + if (builder == null) { + builder = createBuilder(); + } + } + + if (builder != null) { + return new DocumentBuilderProxy(builder, this, version); + } + + return null; + } + + /** {@inheritDoc} */ + public void returnBuilder(DocumentBuilder builder) { + if (!(builder instanceof DocumentBuilderProxy)) { + return; + } + + DocumentBuilderProxy proxiedBuilder = (DocumentBuilderProxy) builder; + if (proxiedBuilder.getOwningPool() != this) { + return; + } + + synchronized (this) { + if (proxiedBuilder.isReturned()) { + return; + } + + if (proxiedBuilder.getPoolVersion() != poolVersion) { + return; + } + + DocumentBuilder unwrappedBuilder = proxiedBuilder.getProxiedBuilder(); + unwrappedBuilder.reset(); + SoftReference builderReference = new SoftReference(unwrappedBuilder); + + if (builderPool.size() < maxPoolSize) { + proxiedBuilder.setReturned(true); + builderPool.push(builderReference); + } + } + } + + /** {@inheritDoc} */ + public Document newDocument() throws XMLParserException { + DocumentBuilder builder = getBuilder(); + Document document = builder.newDocument(); + returnBuilder(builder); + return document; + } + + /** {@inheritDoc} */ + public Document parse(InputStream input) throws XMLParserException { + DocumentBuilder builder = getBuilder(); + try { + Document document = builder.parse(input); + return document; + } catch (SAXException e) { + throw new XMLParserException("Invalid XML", e); + } catch (IOException e) { + throw new XMLParserException("Unable to read XML from input stream", e); + } finally { + returnBuilder(builder); + } + } + + /** {@inheritDoc} */ + public Document parse(Reader input) throws XMLParserException { + DocumentBuilder builder = getBuilder(); + try { + Document document = builder.parse(new InputSource(input)); + return document; + } catch (SAXException e) { + throw new XMLParserException("Invalid XML", e); + } catch (IOException e) { + throw new XMLParserException("Unable to read XML from input stream", e); + } finally { + returnBuilder(builder); + } + } + + /** + * Gets the max number of builders the pool will hold. + * + * @return max number of builders the pool will hold + */ + public int getMaxPoolSize() { + return maxPoolSize; + } + + /** + * Sets the max number of builders the pool will hold. + * + * @param newSize max number of builders the pool will hold + */ + public void setMaxPoolSize(int newSize) { + maxPoolSize = newSize; + } + + /** + * Gets whether new builders will be created when the max pool size is reached. + * + *

Note this method is deprecated and will be removed in the next release. It + * is also currently functionally non-operational.

+ * + * @return whether new builders will be created when the max pool size is reached + * @deprecated + */ + public boolean getCreateBuildersAtPoolLimit() { + return true; + } + + /** + * Sets whether new builders will be created when the max pool size is reached. + * + *

Note this method is deprecated and will be removed in the next release. It + * is also currently functionally non-operational.

+ * + * @param createBuilders whether new builders will be created when the max pool size is reached + * @deprecated + */ + public void setCreateBuildersAtPoolLimit(boolean createBuilders) { + // do nothing + } + + /** + * Gets the builder attributes used when creating builders. This collection is unmodifiable. + * + * @return builder attributes used when creating builders + */ + public Map getBuilderAttributes() { + return Collections.unmodifiableMap(builderAttributes); + } + + /** + * Sets the builder attributes used when creating builders. + * + * @param newAttributes builder attributes used when creating builders + */ + public synchronized void setBuilderAttributes(Map newAttributes) { + builderAttributes = newAttributes; + dirtyBuilderConfiguration = true; + } + + /** + * Gets whether the builders are coalescing. + * + * @return whether the builders are coalescing + */ + public boolean isCoalescing() { + return coalescing; + } + + /** + * Sets whether the builders are coalescing. + * + * @param isCoalescing whether the builders are coalescing + */ + public synchronized void setCoalescing(boolean isCoalescing) { + coalescing = isCoalescing; + dirtyBuilderConfiguration = true; + } + + /** + * Gets whether builders expand entity references. + * + * @return whether builders expand entity references + */ + public boolean isExpandEntityReferences() { + return expandEntityReferences; + } + + /** + * Sets whether builders expand entity references. + * + * @param expand whether builders expand entity references + */ + public synchronized void setExpandEntityReferences(boolean expand) { + expandEntityReferences = expand; + dirtyBuilderConfiguration = true; + } + + /** + * Gets the builders' features. This collection is unmodifiable. + * + * @return the builders' features + */ + public Map getBuilderFeatures() { + return Collections.unmodifiableMap(builderFeatures); + } + + /** + * Sets the the builders' features. + * + * @param newFeatures the builders' features + */ + public synchronized void setBuilderFeatures(Map newFeatures) { + builderFeatures = newFeatures; + dirtyBuilderConfiguration = true; + } + + /** + * Gets whether the builders ignore comments. + * + * @return whether the builders ignore comments + */ + public boolean getIgnoreComments() { + return ignoreComments; + } + + /** + * Sets whether the builders ignore comments. + * + * @param ignore The ignoreComments to set. + */ + public synchronized void setIgnoreComments(boolean ignore) { + ignoreComments = ignore; + dirtyBuilderConfiguration = true; + } + + /** + * Get whether the builders ignore element content whitespace. + * + * @return whether the builders ignore element content whitespace + */ + public boolean isIgnoreElementContentWhitespace() { + return ignoreElementContentWhitespace; + } + + /** + * Sets whether the builders ignore element content whitespace. + * + * @param ignore whether the builders ignore element content whitespace + */ + public synchronized void setIgnoreElementContentWhitespace(boolean ignore) { + ignoreElementContentWhitespace = ignore; + dirtyBuilderConfiguration = true; + } + + /** + * Gets whether the builders are namespace aware. + * + * @return whether the builders are namespace aware + */ + public boolean isNamespaceAware() { + return namespaceAware; + } + + /** + * Sets whether the builders are namespace aware. + * + * @param isNamespaceAware whether the builders are namespace aware + */ + public synchronized void setNamespaceAware(boolean isNamespaceAware) { + namespaceAware = isNamespaceAware; + dirtyBuilderConfiguration = true; + } + + /** {@inheritDoc} */ + public Schema getSchema() { + return schema; + } + + /** {@inheritDoc} */ + public synchronized void setSchema(Schema newSchema) { + schema = newSchema; + if (schema != null) { + setNamespaceAware(true); + builderAttributes.remove("http://java.sun.com/xml/jaxp/properties/schemaSource"); + builderAttributes.remove("http://java.sun.com/xml/jaxp/properties/schemaLanguage"); + } + + dirtyBuilderConfiguration = true; + } + + /** + * Gets whether the builders are validating. + * + * @return whether the builders are validating + */ + public boolean isDTDValidating() { + return dtdValidating; + } + + /** + * Sets whether the builders are validating. + * + * @param isValidating whether the builders are validating + */ + public synchronized void setDTDValidating(boolean isValidating) { + dtdValidating = isValidating; + dirtyBuilderConfiguration = true; + } + + /** + * Gets whether the builders are XInclude aware. + * + * @return whether the builders are XInclude aware + */ + public boolean isXincludeAware() { + return xincludeAware; + } + + /** + * Sets whether the builders are XInclude aware. + * + * @param isXIncludeAware whether the builders are XInclude aware + */ + public synchronized void setXincludeAware(boolean isXIncludeAware) { + xincludeAware = isXIncludeAware; + dirtyBuilderConfiguration = true; + } + + /** + * Gets the current pool version. + * + * @return current pool version + */ + protected long getPoolVersion() { + return poolVersion; + } + + /** + * Gets the size of the current pool storage. + * + * @return current pool storage size + */ + protected int getPoolSize() { + return builderPool.size(); + } + + /** + * Initializes the pool with a new set of configuration options. + * + * @throws XMLParserException thrown if there is a problem initialzing the pool + */ + protected synchronized void initializePool() throws XMLParserException { + if (!dirtyBuilderConfiguration) { + // in case the pool was initialized by some other thread + return; + } + + DocumentBuilderFactory newFactory = DocumentBuilderFactory.newInstance(); + setAttributes(newFactory, builderAttributes); + setFeatures(newFactory, builderFeatures); + newFactory.setCoalescing(coalescing); + newFactory.setExpandEntityReferences(expandEntityReferences); + newFactory.setIgnoringComments(ignoreComments); + newFactory.setIgnoringElementContentWhitespace(ignoreElementContentWhitespace); + newFactory.setNamespaceAware(namespaceAware); + newFactory.setSchema(schema); + newFactory.setValidating(dtdValidating); + newFactory.setXIncludeAware(xincludeAware); + + poolVersion++; + dirtyBuilderConfiguration = false; + builderFactory = newFactory; + builderPool.clear(); + } + + + /** + * Sets document builder attributes. If an attribute is not supported it is ignored. + * + * @param factory document builder factory upon which the attribute will be set + * @param attributes the set of attributes to be set + */ + protected void setAttributes(DocumentBuilderFactory factory, Map attributes) { + if (attributes == null || attributes.isEmpty()) { + return; + } + + for (Map.Entry attribute : attributes.entrySet()) { + try { + log.debug("Setting DocumentBuilderFactory attribute '{}'", attribute.getKey()); + factory.setAttribute(attribute.getKey(), attribute.getValue()); + } catch (IllegalArgumentException e) { + log.warn("DocumentBuilderFactory attribute '{}' is not supported", attribute.getKey()); + } + } + } + + /** + * Sets document builder features. If an features is not supported it is ignored. + * + * @param factory document builder factory upon which the attribute will be set + * @param features the set of features to be set + */ + protected void setFeatures(DocumentBuilderFactory factory, Map features) { + if (features == null || features.isEmpty()) { + return; + } + + for (Map.Entry feature : features.entrySet()) { + try { + log.debug("Setting DocumentBuilderFactory attribute '{}'", feature.getKey()); + factory.setFeature(feature.getKey(), feature.getValue()); + } catch (ParserConfigurationException e) { + log.warn("DocumentBuilderFactory feature '{}' is not supported", feature.getKey()); + } + } + } + + /** + * Creates a new document builder. + * + * @return newly created document builder + * + * @throws XMLParserException thrown if their is a configuration error with the builder factory + */ + protected DocumentBuilder createBuilder() throws XMLParserException { + try { + DocumentBuilder builder = builderFactory.newDocumentBuilder(); + + if (entityResolver != null) { + builder.setEntityResolver(entityResolver); + } + + if (errorHandler != null) { + builder.setErrorHandler(errorHandler); + } + + return builder; + } catch (ParserConfigurationException e) { + log.error("Unable to create new document builder", e); + throw new XMLParserException("Unable to create new document builder", e); + } + } + + /** + * A proxy that prevents the manages document builders retrieved from the parser pool. + */ + protected class DocumentBuilderProxy extends DocumentBuilder { + + /** Builder being proxied. */ + private DocumentBuilder builder; + + /** Pool that owns this parser. */ + private ParserPool owningPool; + + /** Version of the pool when this proxy was created. */ + private long owningPoolVersion; + + /** Track accounting state of whether this builder has been returned to the owning pool. */ + private boolean returned; + + /** + * Constructor. + * + * @param target document builder to proxy + * @param owner the owning pool + * @param version the owning pool's version + */ + public DocumentBuilderProxy(DocumentBuilder target, BasicParserPool owner, long version) { + owningPoolVersion = version; + owningPool = owner; + builder = target; + returned = false; + } + + /** {@inheritDoc} */ + public DOMImplementation getDOMImplementation() { + checkValidState(); + return builder.getDOMImplementation(); + } + + /** {@inheritDoc} */ + public Schema getSchema() { + checkValidState(); + return builder.getSchema(); + } + + /** {@inheritDoc} */ + public boolean isNamespaceAware() { + checkValidState(); + return builder.isNamespaceAware(); + } + + /** {@inheritDoc} */ + public boolean isValidating() { + checkValidState(); + return builder.isValidating(); + } + + /** {@inheritDoc} */ + public boolean isXIncludeAware() { + checkValidState(); + return builder.isXIncludeAware(); + } + + /** {@inheritDoc} */ + public Document newDocument() { + checkValidState(); + return builder.newDocument(); + } + + /** {@inheritDoc} */ + public Document parse(File f) throws SAXException, IOException { + checkValidState(); + return builder.parse(f); + } + + /** {@inheritDoc} */ + public Document parse(InputSource is) throws SAXException, IOException { + checkValidState(); + return builder.parse(is); + } + + /** {@inheritDoc} */ + public Document parse(InputStream is) throws SAXException, IOException { + checkValidState(); + return builder.parse(is); + } + + /** {@inheritDoc} */ + public Document parse(InputStream is, String systemId) throws SAXException, IOException { + checkValidState(); + return builder.parse(is, systemId); + } + + /** {@inheritDoc} */ + public Document parse(String uri) throws SAXException, IOException { + checkValidState(); + return builder.parse(uri); + } + + /** {@inheritDoc} */ + public void reset() { + // ignore, entity resolver and error handler can't be changed + } + + /** {@inheritDoc} */ + public void setEntityResolver(EntityResolver er) { + checkValidState(); + return; + } + + /** {@inheritDoc} */ + public void setErrorHandler(ErrorHandler eh) { + checkValidState(); + return; + } + + /** + * Gets the pool that owns this parser. + * + * @return pool that owns this parser + */ + protected ParserPool getOwningPool() { + return owningPool; + } + + /** + * Gets the version of the pool that owns this parser at the time of the proxy's creation. + * + * @return version of the pool that owns this parser at the time of the proxy's creation + */ + protected long getPoolVersion() { + return owningPoolVersion; + } + + /** + * Gets the proxied document builder. + * + * @return proxied document builder + */ + protected DocumentBuilder getProxiedBuilder() { + return builder; + } + + /** + * Check accounting state as to whether this parser has been returned to the + * owning pool. + * + * @return true if parser has been returned to the owning pool, otherwise false + */ + protected boolean isReturned() { + return returned; + } + + /** + * Set accounting state as to whether this parser has been returned to the + * owning pool. + * + * @param isReturned set true to indicate that parser has been returned to the owning pool + */ + protected void setReturned(boolean isReturned) { + this.returned = isReturned; + } + + /** + * Check whether the parser is in a valid and usable state, and if not, throw a runtime exception. + * + * @throws IllegalStateException thrown if the parser is in a state such that it can not be used + */ + protected void checkValidState() throws IllegalStateException { + if (isReturned()) { + throw new IllegalStateException("DocumentBuilderProxy has already been returned to its owning pool"); + } + } + + /** {@inheritDoc} */ + protected void finalize() throws Throwable { + super.finalize(); + owningPool.returnBuilder(this); + } + } +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/parse/ClasspathResolver.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/parse/ClasspathResolver.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/parse/ClasspathResolver.java 17 Aug 2012 15:17:19 -0000 1.1 @@ -0,0 +1,208 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.parse; + +import java.io.BufferedInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.w3c.dom.ls.LSInput; +import org.w3c.dom.ls.LSResourceResolver; +import org.xml.sax.EntityResolver; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; + +/** + * A entity resolver that resolves an entity's location within the classpath. + * + * Entity URIs must begin with the prefix classpath: and be followed by either an + * absolute or relative classpath. Relative classpaths are relative to this class. + * + * This resolver will not attempt to resolve any other URIs. + */ +public class ClasspathResolver implements EntityResolver, LSResourceResolver { + + /** UR scheme for classpath locations. */ + public static final String CLASSPATH_URI_SCHEME = "classpath:"; + + /** Class logger. */ + private final Logger log = LoggerFactory.getLogger(ClasspathResolver.class); + + /** {@inheritDoc} */ + public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException { + InputStream resourceStream = resolver(publicId, systemId); + if (resourceStream != null) { + return new InputSource(resourceStream); + } + + return null; + } + + /** {@inheritDoc} */ + public LSInput resolveResource(String type, String namespaceURI, String publicId, String systemId, String baseURI) { + return new LSInputImpl(publicId, systemId, resolver(publicId, systemId)); + } + + /** + * Resolves an id against the classpath. System ID is tried first, then public ID. + * + * @param publicId resources public ID + * @param systemId resources system ID + * + * @return resolved resource or null + */ + protected InputStream resolver(String publicId, String systemId) { + String resource = null; + InputStream resourceIns = null; + + if (systemId.startsWith(CLASSPATH_URI_SCHEME)) { + log.trace("Attempting to resolve, within the classpath, the entity with the following system id: {}", + systemId); + resource = systemId.replaceFirst("classpath:", ""); + resourceIns = getClass().getResourceAsStream(resource); + } + + if (resourceIns == null && publicId != null && publicId.startsWith(CLASSPATH_URI_SCHEME)) { + log.trace("Attempting to resolve, within the classpath, the entity with the following public id: {}", + resource); + resource = publicId.replaceFirst("classpath:", ""); + resourceIns = getClass().getResourceAsStream(resource); + } + + if (resourceIns == null) { + log.trace("Entity was not resolved from classpath"); + return null; + } else { + log.trace("Entity resolved from classpath"); + return resourceIns; + } + } + + /** + * Implementation of DOM 3 {@link LSInput}. + */ + protected class LSInputImpl implements LSInput { + + /** Public ID of the resolved resource. */ + private String publicId; + + /** System ID of the resolved recource. */ + private String systemId; + + /** Resolved resource. */ + private BufferedInputStream buffInput; + + /** + * Constructor. + * + * @param pubId public id of the resolved resource + * @param sysId system id of the resolved resource + * @param input resolved resource + */ + public LSInputImpl(String pubId, String sysId, InputStream input) { + publicId = pubId; + systemId = sysId; + buffInput = new BufferedInputStream(input); + } + + /** {@inheritDoc} */ + public String getBaseURI() { + return null; + } + + /** {@inheritDoc} */ + public InputStream getByteStream() { + return buffInput; + } + + /** {@inheritDoc} */ + public boolean getCertifiedText() { + return false; + } + + /** {@inheritDoc} */ + public Reader getCharacterStream() { + return new InputStreamReader(buffInput); + } + + /** {@inheritDoc} */ + public String getEncoding() { + return null; + } + + /** {@inheritDoc} */ + public String getPublicId() { + return publicId; + } + + /** {@inheritDoc} */ + public String getStringData() { + synchronized (buffInput) { + try { + buffInput.reset(); + byte[] input = new byte[buffInput.available()]; + buffInput.read(input); + return new String(input); + } catch (IOException e) { + return null; + } + } + } + + /** {@inheritDoc} */ + public String getSystemId() { + return systemId; + } + + /** {@inheritDoc} */ + public void setBaseURI(String uri) { + } + + /** {@inheritDoc} */ + public void setByteStream(InputStream byteStream) { + } + + /** {@inheritDoc} */ + public void setCertifiedText(boolean isCertifiedText) { + } + + /** {@inheritDoc} */ + public void setCharacterStream(Reader characterStream) { + } + + /** {@inheritDoc} */ + public void setEncoding(String encoding) { + } + + /** {@inheritDoc} */ + public void setPublicId(String id) { + } + + /** {@inheritDoc} */ + public void setStringData(String stringData) { + } + + /** {@inheritDoc} */ + public void setSystemId(String id) { + } + } +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/parse/LoggingErrorHandler.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/parse/LoggingErrorHandler.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/parse/LoggingErrorHandler.java 17 Aug 2012 15:17:20 -0000 1.1 @@ -0,0 +1,59 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.parse; + +import org.slf4j.Logger; +import org.xml.sax.ErrorHandler; +import org.xml.sax.SAXException; +import org.xml.sax.SAXParseException; + +/** + * A SAX error handler that logs errors a {@link Logger} before rethrowing them. + */ +public class LoggingErrorHandler implements ErrorHandler { + + /** Error logger. */ + private Logger log; + + /** + * Constructor. + * + * @param logger logger errors will be written to + */ + public LoggingErrorHandler(Logger logger) { + log = logger; + } + + /** {@inheritDoc} */ + public void error(SAXParseException exception) throws SAXException { + log.error("XML Parsing Error:", exception); + throw exception; + } + + /** {@inheritDoc} */ + public void fatalError(SAXParseException exception) throws SAXException { + log.error("XML Parsing Error", exception); + throw exception; + } + + /** {@inheritDoc} */ + public void warning(SAXParseException exception) throws SAXException { + log.warn("XML Parsing Error", exception); + throw exception; + } +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/parse/ParserPool.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/parse/ParserPool.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/parse/ParserPool.java 17 Aug 2012 15:17:20 -0000 1.1 @@ -0,0 +1,96 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.parse; + +import java.io.InputStream; +import java.io.Reader; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.validation.Schema; + +import org.w3c.dom.Document; + +/** + * A pool of XML parsers. + */ +public interface ParserPool { + + /** + * Gets a builder from the pool. + * + * @return a builder from the pool + * + * @throws XMLParserException thrown if the document builder factory is misconfigured + */ + public DocumentBuilder getBuilder() throws XMLParserException; + + /** + * Returns a builder to the pool. + * + * @param builder the builder to return + */ + public void returnBuilder(DocumentBuilder builder); + + /** + * Convience method for creating a new document with a pooled builder. + * + * @return created document + * + * @throws XMLParserException thrown if there is a problem retrieving a builder + */ + public Document newDocument() throws XMLParserException; + + /** + * Convience method for parsing an XML file using a pooled builder. + * + * @param input XML to parse + * + * @return parsed document + * + * @throws XMLParserException thrown if there is a problem retrieving a builder, the input stream can not be read, + * or the XML was invalid + */ + public Document parse(InputStream input) throws XMLParserException; + + /** + * Convience method for parsing an XML file using a pooled builder. + * + * @param input XML to parse + * + * @return parsed document + * + * @throws XMLParserException thrown if there is a problem retrieving a builder, the input stream can not be read, + * or the XML was invalid + */ + public Document parse(Reader input) throws XMLParserException; + + /** + * Gets the schema builders use to validate. + * + * @return the schema builders use to validate + */ + public Schema getSchema(); + + /** + * Sets the schema builders use to validate. + * + * @param newSchema the schema builders use to validate + */ + public void setSchema(Schema newSchema); + +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/parse/StaticBasicParserPool.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/parse/StaticBasicParserPool.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/parse/StaticBasicParserPool.java 17 Aug 2012 15:17:20 -0000 1.1 @@ -0,0 +1,736 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.parse; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.Reader; +import java.lang.ref.SoftReference; +import java.util.Collections; +import java.util.Map; +import java.util.Stack; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.validation.Schema; + +import org.opensaml.xml.Configuration; +import org.opensaml.xml.util.LazyMap; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.w3c.dom.DOMImplementation; +import org.w3c.dom.Document; +import org.xml.sax.EntityResolver; +import org.xml.sax.ErrorHandler; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; + +/** + * A pool of JAXP 1.3 {@link DocumentBuilder}s. + * + *

This implementation of {@link ParserPool} does not allow its properties to be modified once + * it has been initialized. For an implementation that does support versioned properties over + * time, see {@link BasicParserPool}.

+ * + *

This is a pool implementation of the caching factory variety, and as such imposes no upper bound + * on the number of DocumentBuilders allowed to be concurrently checked out and in use. It does however + * impose a limit on the size of the internal cache of idle builder instances via the value configured + * via {@link #setMaxPoolSize(int)}.

+ * + *

Builders retrieved from this pool may (but are not required to) be returned to the pool with the method + * {@link #returnBuilder(DocumentBuilder)}.

+ * + *

References to builders are kept by way of {@link SoftReference} so that the garbage collector + * may reap the builders if the system is running out of memory.

+ */ +public class StaticBasicParserPool implements ParserPool { + + /** Class logger. */ + private final Logger log = LoggerFactory.getLogger(StaticBasicParserPool.class); + + /** Flag to track whether pool is in the initialized state. */ + private boolean initialized; + + /** Factory used to create new builders. */ + private DocumentBuilderFactory builderFactory; + + /** Cache of document builders. */ + private Stack> builderPool; + + /** Max number of builders allowed in the pool. Default value: 5 */ + private int maxPoolSize; + + /** Builder attributes. */ + private Map builderAttributes; + + /** Whether the builders are coalescing. Default value: true */ + private boolean coalescing; + + /** Whether the builders expand entity references. Default value: true */ + private boolean expandEntityReferences; + + /** Builder features. */ + private Map builderFeatures; + + /** Whether the builders ignore comments. Default value: true */ + private boolean ignoreComments; + + /** Whether the builders ignore element content whitespace. Default value: true */ + private boolean ignoreElementContentWhitespace; + + /** Whether the builders are namespace aware. Default value: true */ + private boolean namespaceAware; + + /** Schema used to validate parsed content. */ + private Schema schema; + + /** Whether the builder should validate. Default value: false */ + private boolean dtdValidating; + + /** Whether the builders are XInclude aware. Default value: false */ + private boolean xincludeAware; + + /** Entity resolver used by builders. */ + private EntityResolver entityResolver; + + /** Error handler used by builders. */ + private ErrorHandler errorHandler; + + /** Constructor. */ + public StaticBasicParserPool() { + initialized = false; + maxPoolSize = 5; + builderPool = new Stack>(); + builderAttributes = new LazyMap(); + coalescing = true; + expandEntityReferences = true; + builderFeatures = new LazyMap(); + ignoreComments = true; + ignoreElementContentWhitespace = true; + namespaceAware = true; + schema = null; + dtdValidating = false; + xincludeAware = false; + errorHandler = new LoggingErrorHandler(log); + + } + + /** + * Initialize the pool. + * + * @throws XMLParserException thrown if pool can not be initialized, + * or if it is already initialized + * + **/ + public synchronized void initialize() throws XMLParserException { + if (initialized) { + throw new XMLParserException("Parser pool was already initialized"); + } + initializeFactory(); + initialized = true; + } + + /** + * Return initialized state. + * + * @return true if pool is initialized, false otherwise + */ + public synchronized boolean isInitialized() { + return initialized; + } + + /** {@inheritDoc} */ + public DocumentBuilder getBuilder() throws XMLParserException { + DocumentBuilder builder = null; + + if (!initialized) { + throw new XMLParserException("Parser pool has not been initialized"); + } + + synchronized(builderPool) { + if (!builderPool.isEmpty()) { + builder = builderPool.pop().get(); + } + } + + // Will be null if either the stack was empty, or the SoftReference + // has been garbage-collected + if (builder == null) { + builder = createBuilder(); + } + + if (builder != null) { + return new DocumentBuilderProxy(builder, this); + } + + return null; + } + + /** {@inheritDoc} */ + public void returnBuilder(DocumentBuilder builder) { + if (!(builder instanceof DocumentBuilderProxy)) { + return; + } + + DocumentBuilderProxy proxiedBuilder = (DocumentBuilderProxy) builder; + if (proxiedBuilder.getOwningPool() != this) { + return; + } + + synchronized (proxiedBuilder) { + if (proxiedBuilder.isReturned()) { + return; + } + // Not strictly true in that it may not actually be pushed back + // into the cache, depending on builderPool.size() below. But + // that's ok. returnBuilder() shouldn't normally be called twice + // on the same builder instance anyway, and it also doesn't matter + // whether a builder is ever logically returned to the pool. + proxiedBuilder.setReturned(true); + } + + DocumentBuilder unwrappedBuilder = proxiedBuilder.getProxiedBuilder(); + unwrappedBuilder.reset(); + SoftReference builderReference = new SoftReference(unwrappedBuilder); + + synchronized(builderPool) { + if (builderPool.size() < maxPoolSize) { + builderPool.push(builderReference); + } + } + } + + /** {@inheritDoc} */ + public Document newDocument() throws XMLParserException { + DocumentBuilder builder = getBuilder(); + Document document = builder.newDocument(); + returnBuilder(builder); + return document; + } + + /** {@inheritDoc} */ + public Document parse(InputStream input) throws XMLParserException { + DocumentBuilder builder = getBuilder(); + try { + Document document = builder.parse(input); + return document; + } catch (SAXException e) { + throw new XMLParserException("Invalid XML", e); + } catch (IOException e) { + throw new XMLParserException("Unable to read XML from input stream", e); + } finally { + returnBuilder(builder); + } + } + + /** {@inheritDoc} */ + public Document parse(Reader input) throws XMLParserException { + DocumentBuilder builder = getBuilder(); + try { + Document document = builder.parse(new InputSource(input)); + return document; + } catch (SAXException e) { + throw new XMLParserException("Invalid XML", e); + } catch (IOException e) { + throw new XMLParserException("Unable to read XML from input stream", e); + } finally { + returnBuilder(builder); + } + } + + /** + * Gets the max number of builders the pool will hold. + * + * @return max number of builders the pool will hold + */ + public int getMaxPoolSize() { + return maxPoolSize; + } + + /** + * Sets the max number of builders the pool will hold. + * + * @param newSize max number of builders the pool will hold + */ + public void setMaxPoolSize(int newSize) { + checkValidModifyState(); + maxPoolSize = newSize; + } + + /** + * Gets the builder attributes used when creating builders. This collection is unmodifiable. + * + * @return builder attributes used when creating builders + */ + public Map getBuilderAttributes() { + return Collections.unmodifiableMap(builderAttributes); + } + + /** + * Sets the builder attributes used when creating builders. + * + * @param newAttributes builder attributes used when creating builders + */ + public void setBuilderAttributes(Map newAttributes) { + checkValidModifyState(); + builderAttributes = newAttributes; + } + + /** + * Gets whether the builders are coalescing. + * + * @return whether the builders are coalescing + */ + public boolean isCoalescing() { + return coalescing; + } + + /** + * Sets whether the builders are coalescing. + * + * @param isCoalescing whether the builders are coalescing + */ + public void setCoalescing(boolean isCoalescing) { + checkValidModifyState(); + coalescing = isCoalescing; + } + + /** + * Gets whether builders expand entity references. + * + * @return whether builders expand entity references + */ + public boolean isExpandEntityReferences() { + return expandEntityReferences; + } + + /** + * Sets whether builders expand entity references. + * + * @param expand whether builders expand entity references + */ + public void setExpandEntityReferences(boolean expand) { + checkValidModifyState(); + expandEntityReferences = expand; + } + + /** + * Gets the builders' features. This collection is unmodifiable. + * + * @return the builders' features + */ + public Map getBuilderFeatures() { + return Collections.unmodifiableMap(builderFeatures); + } + + /** + * Sets the the builders' features. + * + * @param newFeatures the builders' features + */ + public void setBuilderFeatures(Map newFeatures) { + checkValidModifyState(); + builderFeatures = newFeatures; + } + + /** + * Gets whether the builders ignore comments. + * + * @return whether the builders ignore comments + */ + public boolean getIgnoreComments() { + return ignoreComments; + } + + /** + * Sets whether the builders ignore comments. + * + * @param ignore The ignoreComments to set. + */ + public void setIgnoreComments(boolean ignore) { + checkValidModifyState(); + ignoreComments = ignore; + } + + /** + * Get whether the builders ignore element content whitespace. + * + * @return whether the builders ignore element content whitespace + */ + public boolean isIgnoreElementContentWhitespace() { + return ignoreElementContentWhitespace; + } + + /** + * Sets whether the builders ignore element content whitespace. + * + * @param ignore whether the builders ignore element content whitespace + */ + public void setIgnoreElementContentWhitespace(boolean ignore) { + checkValidModifyState(); + ignoreElementContentWhitespace = ignore; + } + + /** + * Gets whether the builders are namespace aware. + * + * @return whether the builders are namespace aware + */ + public boolean isNamespaceAware() { + return namespaceAware; + } + + /** + * Sets whether the builders are namespace aware. + * + * @param isNamespaceAware whether the builders are namespace aware + */ + public void setNamespaceAware(boolean isNamespaceAware) { + checkValidModifyState(); + namespaceAware = isNamespaceAware; + } + + /** {@inheritDoc} */ + public Schema getSchema() { + return schema; + } + + /** {@inheritDoc} */ + public synchronized void setSchema(Schema newSchema) { + // Note this method is synchronized because it is more than just an atomic assignment. + // Don't want inconsistent data in the factory via initializeFactory(), also synchronized. + checkValidModifyState(); + schema = newSchema; + if (schema != null) { + setNamespaceAware(true); + builderAttributes.remove("http://java.sun.com/xml/jaxp/properties/schemaSource"); + builderAttributes.remove("http://java.sun.com/xml/jaxp/properties/schemaLanguage"); + } + } + + /** + * Gets whether the builders are validating. + * + * @return whether the builders are validating + */ + public boolean isDTDValidating() { + return dtdValidating; + } + + /** + * Sets whether the builders are validating. + * + * @param isValidating whether the builders are validating + */ + public void setDTDValidating(boolean isValidating) { + checkValidModifyState(); + dtdValidating = isValidating; + } + + /** + * Gets whether the builders are XInclude aware. + * + * @return whether the builders are XInclude aware + */ + public boolean isXincludeAware() { + return xincludeAware; + } + + /** + * Sets whether the builders are XInclude aware. + * + * @param isXIncludeAware whether the builders are XInclude aware + */ + public void setXincludeAware(boolean isXIncludeAware) { + checkValidModifyState(); + xincludeAware = isXIncludeAware; + } + + /** + * Gets the size of the current pool storage. + * + * @return current pool storage size + */ + protected int getPoolSize() { + return builderPool.size(); + } + + /** + * Check that pool is in a valid state to be modified. + */ + protected void checkValidModifyState() { + if (initialized) { + throw new IllegalStateException("Pool is already initialized, property changes not allowed"); + } + } + + /** + * Initializes the pool with a new set of configuration options. + * + * @throws XMLParserException thrown if there is a problem initialzing the pool + */ + protected synchronized void initializeFactory() throws XMLParserException { + DocumentBuilderFactory newFactory = DocumentBuilderFactory.newInstance(); + setAttributes(newFactory, builderAttributes); + setFeatures(newFactory, builderFeatures); + newFactory.setCoalescing(coalescing); + newFactory.setExpandEntityReferences(expandEntityReferences); + newFactory.setIgnoringComments(ignoreComments); + newFactory.setIgnoringElementContentWhitespace(ignoreElementContentWhitespace); + newFactory.setNamespaceAware(namespaceAware); + newFactory.setSchema(schema); + newFactory.setValidating(dtdValidating); + newFactory.setXIncludeAware(xincludeAware); + builderFactory = newFactory; + } + + /** + * Sets document builder attributes. If an attribute is not supported it is ignored. + * + * @param factory document builder factory upon which the attribute will be set + * @param attributes the set of attributes to be set + */ + protected void setAttributes(DocumentBuilderFactory factory, Map attributes) { + if (attributes == null || attributes.isEmpty()) { + return; + } + + for (Map.Entry attribute : attributes.entrySet()) { + try { + log.debug("Setting DocumentBuilderFactory attribute '{}'", attribute.getKey()); + factory.setAttribute(attribute.getKey(), attribute.getValue()); + } catch (IllegalArgumentException e) { + log.warn("DocumentBuilderFactory attribute '{}' is not supported", attribute.getKey()); + } + } + } + + /** + * Sets document builder features. If an features is not supported it is ignored. + * + * @param factory document builder factory upon which the attribute will be set + * @param features the set of features to be set + */ + protected void setFeatures(DocumentBuilderFactory factory, Map features) { + if (features == null || features.isEmpty()) { + return; + } + + for (Map.Entry feature : features.entrySet()) { + try { + log.debug("Setting DocumentBuilderFactory attribute '{}'", feature.getKey()); + factory.setFeature(feature.getKey(), feature.getValue()); + } catch (ParserConfigurationException e) { + log.warn("DocumentBuilderFactory feature '{}' is not supported", feature.getKey()); + } + } + } + + /** + * Creates a new document builder. + * + * @return newly created document builder + * + * @throws XMLParserException thrown if their is a configuration error with the builder factory + */ + protected DocumentBuilder createBuilder() throws XMLParserException { + try { + DocumentBuilder builder = builderFactory.newDocumentBuilder(); + + if (entityResolver != null) { + builder.setEntityResolver(entityResolver); + } + + if (errorHandler != null) { + builder.setErrorHandler(errorHandler); + } + + return builder; + } catch (ParserConfigurationException e) { + log.error("Unable to create new document builder", e); + throw new XMLParserException("Unable to create new document builder", e); + } + } + + /** + * A proxy that prevents the manages document builders retrieved from the parser pool. + */ + protected class DocumentBuilderProxy extends DocumentBuilder { + + /** Builder being proxied. */ + private DocumentBuilder builder; + + /** Pool that owns this parser. */ + private ParserPool owningPool; + + /** Track accounting state of whether this builder has been returned to the owning pool. */ + private boolean returned; + + /** + * Constructor. + * + * @param target document builder to proxy + * @param owner the owning pool + */ + public DocumentBuilderProxy(DocumentBuilder target, StaticBasicParserPool owner) { + owningPool = owner; + builder = target; + returned = false; + } + + /** {@inheritDoc} */ + public DOMImplementation getDOMImplementation() { + checkValidState(); + return builder.getDOMImplementation(); + } + + /** {@inheritDoc} */ + public Schema getSchema() { + checkValidState(); + return builder.getSchema(); + } + + /** {@inheritDoc} */ + public boolean isNamespaceAware() { + checkValidState(); + return builder.isNamespaceAware(); + } + + /** {@inheritDoc} */ + public boolean isValidating() { + checkValidState(); + return builder.isValidating(); + } + + /** {@inheritDoc} */ + public boolean isXIncludeAware() { + checkValidState(); + return builder.isXIncludeAware(); + } + + /** {@inheritDoc} */ + public Document newDocument() { + checkValidState(); + return builder.newDocument(); + } + + /** {@inheritDoc} */ + public Document parse(File f) throws SAXException, IOException { + checkValidState(); + return builder.parse(f); + } + + /** {@inheritDoc} */ + public Document parse(InputSource is) throws SAXException, IOException { + checkValidState(); + return builder.parse(is); + } + + /** {@inheritDoc} */ + public Document parse(InputStream is) throws SAXException, IOException { + checkValidState(); + return builder.parse(is); + } + + /** {@inheritDoc} */ + public Document parse(InputStream is, String systemId) throws SAXException, IOException { + checkValidState(); + return builder.parse(is, systemId); + } + + /** {@inheritDoc} */ + public Document parse(String uri) throws SAXException, IOException { + checkValidState(); + return builder.parse(uri); + } + + /** {@inheritDoc} */ + public void reset() { + // ignore, entity resolver and error handler can't be changed + } + + /** {@inheritDoc} */ + public void setEntityResolver(EntityResolver er) { + checkValidState(); + return; + } + + /** {@inheritDoc} */ + public void setErrorHandler(ErrorHandler eh) { + checkValidState(); + return; + } + + /** + * Gets the pool that owns this parser. + * + * @return pool that owns this parser + */ + protected ParserPool getOwningPool() { + return owningPool; + } + + /** + * Gets the proxied document builder. + * + * @return proxied document builder + */ + protected DocumentBuilder getProxiedBuilder() { + return builder; + } + + /** + * Check accounting state as to whether this parser has been returned to the + * owning pool. + * + * @return true if parser has been returned to the owning pool, otherwise false + */ + protected boolean isReturned() { + return returned; + } + + /** + * Set accounting state as to whether this parser has been returned to the + * owning pool. + * + * @param isReturned set true to indicate that parser has been returned to the owning pool + */ + protected void setReturned(boolean isReturned) { + this.returned = isReturned; + } + + /** + * Check whether the parser is in a valid and usable state, and if not, throw a runtime exception. + * + * @throws IllegalStateException thrown if the parser is in a state such that it can not be used + */ + protected void checkValidState() throws IllegalStateException { + if (isReturned()) { + throw new IllegalStateException("DocumentBuilderProxy has already been returned to its owning pool"); + } + } + + /** {@inheritDoc} */ + protected void finalize() throws Throwable { + super.finalize(); + owningPool.returnBuilder(this); + } + } +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/parse/XMLParserException.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/parse/XMLParserException.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/parse/XMLParserException.java 17 Aug 2012 15:17:20 -0000 1.1 @@ -0,0 +1,64 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.parse; + +/** + * An exception thrown when there is a problem creating an XML parser or parsing XML with on. + */ +public class XMLParserException extends Exception { + + /** + * Serial version UID. + */ + private static final long serialVersionUID = 7260425832643941776L; + + /** + * Constructor. + */ + public XMLParserException() { + + } + + /** + * Constructor. + * + * @param message exception message + */ + public XMLParserException(String message) { + super(message); + } + + /** + * Constructor. + * + * @param wrappedException exception to be wrapped by this one + */ + public XMLParserException(Exception wrappedException) { + super(wrappedException); + } + + /** + * Constructor. + * + * @param message exception message + * @param wrappedException exception to be wrapped by this one + */ + public XMLParserException(String message, Exception wrappedException) { + super(message, wrappedException); + } +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/parse/package.html =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/parse/package.html,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/parse/package.html 17 Aug 2012 15:17:19 -0000 1.1 @@ -0,0 +1,9 @@ + + +Classes for managing pools of DOM parsers (DocumentBuilders). + +

+DOM parsers can be very expensive to create, the ParserPool helps by allows them to be +cached and reused. + + \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/schema/SchemaBuilder.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/schema/SchemaBuilder.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/schema/SchemaBuilder.java 17 Aug 2012 15:17:20 -0000 1.1 @@ -0,0 +1,282 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.schema; + +import java.io.File; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; + +import javax.xml.XMLConstants; +import javax.xml.transform.Source; +import javax.xml.transform.stream.StreamSource; +import javax.xml.validation.Schema; +import javax.xml.validation.SchemaFactory; + +import org.opensaml.xml.parse.LoggingErrorHandler; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.xml.sax.SAXException; + +/** A helper class for building {@link Schema} from a set of input. */ +public final class SchemaBuilder { + + /** Language of the schema files. */ + public static enum SchemaLanguage { + + /** W3 XML Schema. */ + XML("xsd"), + + /** OASIS RELAX NG Schema. */ + RELAX("rng"); + + /** File extension used for the schema files. */ + private String schemaFileExtension; + + /** + * Constructor. + * + * @param extension file extension used for the schema files + */ + private SchemaLanguage(String extension) { + schemaFileExtension = extension; + } + + /** + * Gets the file extension used for the schema files. + * + * @return file extension used for the schema files + */ + public String getSchemaFileExtension() { + return schemaFileExtension; + } + }; + + /** Constructor. */ + private SchemaBuilder() {} + + /** + * Builds a schema from the given schema source. + * + * @param lang schema language, must not be null + * @param schemaFileOrDirectory file or directory which contains schema sources + * + * @return the constructed schema + * + * @throws SAXException thrown if there is a problem converting the schema sources in to a schema + */ + public static Schema buildSchema(SchemaLanguage lang, String schemaFileOrDirectory) throws SAXException { + if(schemaFileOrDirectory == null){ + return null; + } + + return buildSchema(lang, new File(schemaFileOrDirectory)); + } + + /** + * Builds a schema from the given schema sources. + * + * @param lang schema language, must not be null + * @param schemaFilesOrDirectories files or directories which contains schema sources + * + * @return the constructed schema + * + * @throws SAXException thrown if there is a problem converting the schema sources in to a schema + */ + public static Schema buildSchema(SchemaLanguage lang, String[] schemaFilesOrDirectories) throws SAXException { + if(schemaFilesOrDirectories == null || schemaFilesOrDirectories.length == 0){ + return null; + } + + return buildSchema(lang, schemaFilesOrDirectories); + } + + /** + * Builds a schema from the given schema source. + * + * @param lang schema language, must not be null + * @param schemaFileOrDirectory file or directory which contains schema sources + * + * @return the constructed schema + * + * @throws SAXException thrown if there is a problem converting the schema sources in to a schema + */ + public static Schema buildSchema(SchemaLanguage lang, File schemaFileOrDirectory) throws SAXException { + if(schemaFileOrDirectory == null){ + return null; + } + + return buildSchema(lang, new File[]{schemaFileOrDirectory}); + } + + /** + * Builds a schema from the given schema sources. + * + * @param lang schema language, must not be null + * @param schemaFilesOrDirectories files or directories which contains schema sources + * + * @return the constructed schema + * + * @throws SAXException thrown if there is a problem converting the schema sources in to a schema + */ + public static Schema buildSchema(SchemaLanguage lang, File[] schemaFilesOrDirectories) throws SAXException { + if(schemaFilesOrDirectories == null || schemaFilesOrDirectories.length == 0){ + return null; + } + + ArrayList schemaFiles = new ArrayList(); + getSchemaFiles(lang, schemaFilesOrDirectories, schemaFiles); + + if(schemaFiles.isEmpty()){ + return null; + } + + ArrayList schemaSources = new ArrayList(); + for(File schemaFile : schemaFiles){ + schemaSources.add(new StreamSource(schemaFile)); + } + return buildSchema(lang, schemaSources.toArray(new Source[]{})); + } + + /** + * Builds a schema from the given schema source. + * + * @param lang schema language, must not be null + * @param schemaSource schema source + * + * @return the constructed schema + * + * @throws SAXException thrown if there is a problem converting the schema sources in to a schema + */ + public static Schema buildSchema(SchemaLanguage lang, InputStream schemaSource) throws SAXException { + if(schemaSource == null){ + return null; + } + + return buildSchema(lang, new StreamSource[] { new StreamSource(schemaSource) }); + } + + /** + * Builds a schema from the given schema sources. + * + * @param lang schema language, must not be null + * @param schemaSources schema sources + * + * @return the constructed schema + * + * @throws SAXException thrown if there is a problem converting the schema sources in to a schema + */ + public static Schema buildSchema(SchemaLanguage lang, InputStream[] schemaSources) throws SAXException { + if(schemaSources == null || schemaSources.length == 0){ + return null; + } + + ArrayList sources = new ArrayList(); + for (InputStream schemaSource : schemaSources) { + if (schemaSource == null) { + continue; + } + sources.add(new StreamSource(schemaSource)); + } + + if (sources.isEmpty()) { + return null; + } + + return buildSchema(lang, sources.toArray(new Source[] {})); + } + + /** + * Gets all of the schema files in the given set of readable files, directories or subdirectories. + * + * @param lang schema language, must not be null + * @param schemaFilesOrDirectories files and directories which may contain schema files + * @param accumulatedSchemaFiles list that accumulates the schema files + */ + protected static void getSchemaFiles(SchemaLanguage lang, File[] schemaFilesOrDirectories, + List accumulatedSchemaFiles) { + Logger log = getLogger(); + + if(lang == null){ + throw new IllegalArgumentException("Schema language may not be null"); + } + + if (schemaFilesOrDirectories == null || schemaFilesOrDirectories.length == 0) { + return; + } + + for (File handle : schemaFilesOrDirectories) { + if (handle == null) { + continue; + } + + if (!handle.canRead()) { + log.debug("Ignoring '{}', no read permission", handle.getAbsolutePath()); + } + + if (handle.isFile() && handle.getName().endsWith(lang.getSchemaFileExtension())) { + log.debug("Added schema source '{}'", handle.getAbsolutePath()); + accumulatedSchemaFiles.add(handle); + } + + if (handle.isDirectory()) { + getSchemaFiles(lang, handle.listFiles(), accumulatedSchemaFiles); + } + } + } + + /** + * Builds a schema from the given schema sources. + * + * @param lang schema language, must not be null + * @param schemaSources schema sources, must not be null + * + * @return the constructed schema + * + * @throws SAXException thrown if there is a problem converting the schema sources in to a schema + */ + protected static Schema buildSchema(SchemaLanguage lang, Source[] schemaSources) throws SAXException { + if(lang == null){ + throw new IllegalArgumentException("Schema language may not be null"); + } + + if(schemaSources == null){ + throw new IllegalArgumentException("Schema sources may not be null"); + } + + SchemaFactory schemaFactory; + + if (lang == SchemaLanguage.XML) { + schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); + } else { + schemaFactory = SchemaFactory.newInstance(XMLConstants.RELAXNG_NS_URI); + } + + schemaFactory.setErrorHandler(new LoggingErrorHandler(LoggerFactory.getLogger(SchemaBuilder.class))); + return schemaFactory.newSchema(schemaSources); + } + + /** + * Get an SLF4J Logger. + * + * @return a Logger instance + */ + private static Logger getLogger() { + return LoggerFactory.getLogger(SchemaBuilder.class); + } +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/schema/XSAny.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/schema/XSAny.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/schema/XSAny.java 17 Aug 2012 15:17:21 -0000 1.1 @@ -0,0 +1,51 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.schema; + +import javax.xml.namespace.QName; + +import org.opensaml.xml.AttributeExtensibleXMLObject; +import org.opensaml.xml.ElementExtensibleXMLObject; +import org.opensaml.xml.util.XMLConstants; +import org.opensaml.xml.validation.ValidatingXMLObject; + +/** + * Represents the schema Any type. + */ +public interface XSAny extends ElementExtensibleXMLObject, AttributeExtensibleXMLObject, ValidatingXMLObject { + + /** Local name of the XSI type. */ + public static final String TYPE_LOCAL_NAME = "anyType"; + + /** QName of the XSI type. */ + public static final QName TYPE_NAME = new QName(XMLConstants.XSD_NS, TYPE_LOCAL_NAME, XMLConstants.XSD_PREFIX); + + /** + * Gets the text content for the DOM Element. + * + * @return the text content for the DOM Element + */ + public String getTextContent(); + + /** + * Sets the text content for the DOM Element. + * + * @param newContent the text content for the DOM Element + */ + public void setTextContent(String newContent); +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/schema/XSBase64Binary.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/schema/XSBase64Binary.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/schema/XSBase64Binary.java 17 Aug 2012 15:17:20 -0000 1.1 @@ -0,0 +1,49 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.schema; + +import javax.xml.namespace.QName; + +import org.opensaml.xml.util.XMLConstants; +import org.opensaml.xml.validation.ValidatingXMLObject; + +/** + * XMLObject that represents an XML Schema base64Binary. + */ +public interface XSBase64Binary extends ValidatingXMLObject { + + /** Local name of the XSI type. */ + public static final String TYPE_LOCAL_NAME = "base64Binary"; + + /** QName of the XSI type. */ + public static final QName TYPE_NAME = new QName(XMLConstants.XSD_NS, TYPE_LOCAL_NAME, XMLConstants.XSD_PREFIX); + + /** + * Gets the base64-encoded binary value. + * + * @return the string + */ + public String getValue(); + + /** + * Sets the base64-encoded binary value. + * + * @param newValue the string value + */ + public void setValue(String newValue); +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/schema/XSBoolean.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/schema/XSBoolean.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/schema/XSBoolean.java 17 Aug 2012 15:17:20 -0000 1.1 @@ -0,0 +1,41 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.schema; + +import org.opensaml.xml.validation.ValidatingXMLObject; + +/** + * XSBoolean is the xs:boolean schema type. + */ +public abstract interface XSBoolean extends ValidatingXMLObject { + + /** + * Returns the XSBooleanValue value. + * + * @return the {@link XSBooleanValue} value + */ + public XSBooleanValue getValue(); + + /** + * Sets the XSBooleanValue value. + * + * @param value The {@link XSBooleanValue} value + */ + public void setValue(XSBooleanValue value); + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/schema/XSBooleanValue.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/schema/XSBooleanValue.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/schema/XSBooleanValue.java 17 Aug 2012 15:17:20 -0000 1.1 @@ -0,0 +1,181 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.schema; + +import org.opensaml.xml.util.DatatypeHelper; + +/** + * A class representing a boolean attribute. This class tracks the usage of the literals {true, false, 1, 0} to ensure + * proper roundtripping when unmarshalling/marshalling. + */ +public class XSBooleanValue { + + /** Whether to use the numeric representation of the lexical one. */ + private boolean numeric; + + /** Value of this boolean. */ + private Boolean value; + + /** + * Constructor. Uses lexical representation and sets value to null. + */ + public XSBooleanValue() { + numeric = false; + value = null; + } + + /** + * Constructor. + * + * @param newValue the value + * @param numericRepresentation whether to use a numeric or lexical representation + */ + public XSBooleanValue(Boolean newValue, boolean numericRepresentation) { + numeric = numericRepresentation; + value = newValue; + } + + /** + * Gets the boolean value. + * + * @return the boolean value + */ + public Boolean getValue() { + return value; + } + + /** + * Sets the boolean value. + * + * @param newValue the boolean value + */ + public void setValue(Boolean newValue) { + value = newValue; + } + + /** + * Gets whether to use the numeric or lexical representation. + * + * @return whether to use the numeric or lexical representation + */ + public boolean isNumericRepresentation() { + return numeric; + } + + /** + * Sets whether to use the numeric or lexical representation. + * + * @param numericRepresentation whether to use the numeric or lexical representation + */ + public void setNumericRepresentation(boolean numericRepresentation) { + this.numeric = numericRepresentation; + } + + /** {@inheritDoc} */ + public int hashCode(){ + int hash; + if(numeric){ + if(value == null){ + hash = 0; + }else if(value.booleanValue()){ + hash = 1; + }else { + hash = 3; + } + }else{ + if(value == null){ + hash = 4; + }else if(value.booleanValue()){ + hash = 5; + }else { + hash = 6; + } + } + + return hash; + } + + /** {@inheritDoc} */ + public boolean equals(Object obj){ + if(obj == this){ + return true; + } + + if(obj instanceof XSBooleanValue){ + return hashCode() == obj.hashCode(); + } + + return false; + } + + /** {@inheritDoc} */ + public String toString() { + return toString(value, numeric); + } + + /** + * Converts a boolean value into a string. If using the numeric representations and the value is true then "1" is + * returned or "0" if the value is false. If lexical representation is used "true" and "false" will be returned. If + * the given value is null, then "false" is returned. + * + * @param value the boolean value + * @param numericRepresentation whether to use numeric of lexical representation + * + * @return the textual representation + */ + public static String toString(Boolean value, boolean numericRepresentation) { + if (value == null) { + return "false"; + } + + if (numericRepresentation) { + if (value.booleanValue()) { + return "1"; + } else { + return "0"; + } + } else { + return value.toString(); + } + } + + /** + * Parses a string meant to represent a boolean. If the string is "1" or "0" the returned object will use a numeric + * representation and have a value of TRUE or FALSE, respectively. If the string is "true" the returned object will + * use a lexical representation and have a value of TRUE. If the string is anything else the returned object will + * use a lexical representation and have a value of FALSE. + * + * @param booleanString the string to parse + * + * @return the boolean value + */ + public static XSBooleanValue valueOf(String booleanString) { + String trimmedBooleanString = DatatypeHelper.safeTrimOrNullString(booleanString); + if (trimmedBooleanString != null) { + if (trimmedBooleanString.equals("1")) { + return new XSBooleanValue(Boolean.TRUE, true); + } else if (trimmedBooleanString.equals("0")) { + return new XSBooleanValue(Boolean.FALSE, true); + } else if (trimmedBooleanString.equals("true")) { + return new XSBooleanValue(Boolean.TRUE, false); + } + } + + return new XSBooleanValue(Boolean.FALSE, false); + } +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/schema/XSDateTime.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/schema/XSDateTime.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/schema/XSDateTime.java 17 Aug 2012 15:17:21 -0000 1.1 @@ -0,0 +1,75 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.schema; + +import javax.xml.namespace.QName; + +import org.joda.time.DateTime; +import org.joda.time.format.DateTimeFormatter; +import org.opensaml.xml.util.XMLConstants; +import org.opensaml.xml.validation.ValidatingXMLObject; + +/** + * XMLObject that represents an XML Schema dateTime. + */ +public interface XSDateTime extends ValidatingXMLObject { + + /** Local name of the XSI type. */ + public static final String TYPE_LOCAL_NAME = "dateTime"; + + /** QName of the XSI type. */ + public static final QName TYPE_NAME = new QName(XMLConstants.XSD_NS, TYPE_LOCAL_NAME, XMLConstants.XSD_PREFIX); + + /** + * Gets the dateTime value. + * + * @return the dateTime value + */ + public DateTime getValue(); + + /** + * Sets the dateTime value. + * + * @param newValue the dateTime value + */ + public void setValue(DateTime newValue); + + /** + * Get the {@link DateTimeFormatter} to be used when stringifying + * the {@link DateTime} value. + * + *

Defaults to the formatter constructed by calling: + * org.joda.time.format.ISODateTimeFormat.dateTime().withChronology(org.joda.time.chrono.ISOChronology.getInstanceUTC() + *

+ * + * @return the currently configured formatter + */ + public DateTimeFormatter getDateTimeFormatter(); + + /** + * Set the {@link DateTimeFormatter} to be used when stringifying + * the {@link DateTime} value. + * + *

Defaults to the formatter constructed by calling: + * org.joda.time.format.ISODateTimeFormat.dateTime().withChronology(org.joda.time.chrono.ISOChronology.getInstanceUTC() + *

+ * + * @param newFormatter the new formatter + */ + public void setDateTimeFormatter(DateTimeFormatter newFormatter); +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/schema/XSInteger.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/schema/XSInteger.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/schema/XSInteger.java 17 Aug 2012 15:17:20 -0000 1.1 @@ -0,0 +1,49 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.schema; + +import javax.xml.namespace.QName; + +import org.opensaml.xml.util.XMLConstants; +import org.opensaml.xml.validation.ValidatingXMLObject; + +/** + * XMLObject that represents an XML Schema Integer. + */ +public interface XSInteger extends ValidatingXMLObject { + + /** Local name of the XSI type. */ + public static final String TYPE_LOCAL_NAME = "integer"; + + /** QName of the XSI type. */ + public static final QName TYPE_NAME = new QName(XMLConstants.XSD_NS, TYPE_LOCAL_NAME, XMLConstants.XSD_PREFIX); + + /** + * Gets the integer. + * + * @return the integer + */ + public Integer getValue(); + + /** + * Sets the integer. + * + * @param newValue the integer value + */ + public void setValue(Integer newValue); +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/schema/XSQName.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/schema/XSQName.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/schema/XSQName.java 17 Aug 2012 15:17:20 -0000 1.1 @@ -0,0 +1,49 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.schema; + +import javax.xml.namespace.QName; + +import org.opensaml.xml.util.XMLConstants; +import org.opensaml.xml.validation.ValidatingXMLObject; + +/** + * XMLObject that represents an XML schema QName content bearing element. + */ +public interface XSQName extends ValidatingXMLObject { + + /** Local name of the XSI type. */ + public static final String TYPE_LOCAL_NAME = "QName"; + + /** QName of the XSI type. */ + public static final QName TYPE_NAME = new QName(XMLConstants.XSD_NS, TYPE_LOCAL_NAME, XMLConstants.XSD_PREFIX); + + /** + * Gets the QName content of the element. + * + * @return the QName content of the element + */ + public QName getValue(); + + /** + * Sets the QName content of the element. + * + * @param newValue the QName content of the element + */ + public void setValue(QName newValue); +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/schema/XSString.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/schema/XSString.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/schema/XSString.java 17 Aug 2012 15:17:20 -0000 1.1 @@ -0,0 +1,49 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.schema; + +import javax.xml.namespace.QName; + +import org.opensaml.xml.util.XMLConstants; +import org.opensaml.xml.validation.ValidatingXMLObject; + +/** + * XMLObject that represents an XML Schema String. + */ +public interface XSString extends ValidatingXMLObject { + + /** Local name of the XSI type. */ + public static final String TYPE_LOCAL_NAME = "string"; + + /** QName of the XSI type. */ + public static final QName TYPE_NAME = new QName(XMLConstants.XSD_NS, TYPE_LOCAL_NAME, XMLConstants.XSD_PREFIX); + + /** + * Gets the string. + * + * @return the string + */ + public String getValue(); + + /** + * Sets the string. + * + * @param newValue the string value + */ + public void setValue(String newValue); +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/schema/XSURI.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/schema/XSURI.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/schema/XSURI.java 17 Aug 2012 15:17:20 -0000 1.1 @@ -0,0 +1,49 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.schema; + +import javax.xml.namespace.QName; + +import org.opensaml.xml.util.XMLConstants; +import org.opensaml.xml.validation.ValidatingXMLObject; + +/** + * XMLObject that represents an XML schema URI content bearing element. + */ +public interface XSURI extends ValidatingXMLObject { + + /** Local name of the XSI type. */ + public static final String TYPE_LOCAL_NAME = "anyURI"; + + /** QName of the XSI type. */ + public static final QName TYPE_NAME = new QName(XMLConstants.XSD_NS, TYPE_LOCAL_NAME, XMLConstants.XSD_PREFIX); + + /** + * Gets the URI content of the element. + * + * @return the URI content of the element + */ + public String getValue(); + + /** + * Sets the URI content of the element. + * + * @param newValue the URI content of the element + */ + public void setValue(String newValue); +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/schema/package.html =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/schema/package.html,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/schema/package.html 17 Aug 2012 15:17:20 -0000 1.1 @@ -0,0 +1,6 @@ + + +Interfaces for XMLObjects that represent XML schema types. + + + \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/schema/impl/XSAnyBuilder.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/schema/impl/XSAnyBuilder.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/schema/impl/XSAnyBuilder.java 17 Aug 2012 15:17:10 -0000 1.1 @@ -0,0 +1,32 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.schema.impl; + +import org.opensaml.xml.AbstractXMLObjectBuilder; +import org.opensaml.xml.schema.XSAny; + +/** + * Builder of {@link XSAnyImpl}s. + */ +public class XSAnyBuilder extends AbstractXMLObjectBuilder { + + /** {@inheritDoc} */ + public XSAny buildObject(String namespaceURI, String localName, String namespacePrefix) { + return new XSAnyImpl(namespaceURI, localName, namespacePrefix); + } +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/schema/impl/XSAnyImpl.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/schema/impl/XSAnyImpl.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/schema/impl/XSAnyImpl.java 17 Aug 2012 15:17:10 -0000 1.1 @@ -0,0 +1,88 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.schema.impl; + +import java.util.Collections; +import java.util.List; + +import javax.xml.namespace.QName; + +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.schema.XSAny; +import org.opensaml.xml.util.AttributeMap; +import org.opensaml.xml.util.IndexedXMLObjectChildrenList; +import org.opensaml.xml.validation.AbstractValidatingXMLObject; + +/** + * Concrete implementation of {@link XSAny}. + */ +public class XSAnyImpl extends AbstractValidatingXMLObject implements XSAny { + + /** Child XMLObjects. */ + private IndexedXMLObjectChildrenList unknownXMLObjects; + + /** Attributes for this element. */ + private AttributeMap unknownAttributes; + + /** Text content of the element. */ + private String textContent; + + /** + * Constructor. + * + * @param namespaceURI the namespace the element is in + * @param elementLocalName the local name of the XML element this Object represents + * @param namespacePrefix the prefix for the given namespace + */ + protected XSAnyImpl(String namespaceURI, String elementLocalName, String namespacePrefix) { + super(namespaceURI, elementLocalName, namespacePrefix); + + unknownXMLObjects = new IndexedXMLObjectChildrenList(this); + unknownAttributes = new AttributeMap(this); + } + + /** {@inheritDoc} */ + public String getTextContent() { + return textContent; + } + + /** {@inheritDoc} */ + public void setTextContent(String newContent) { + textContent = prepareForAssignment(textContent, newContent); + } + + /** {@inheritDoc} */ + public List getUnknownXMLObjects() { + return unknownXMLObjects; + } + + /** {@inheritDoc} */ + public List getUnknownXMLObjects(QName typeOrName) { + return (List) unknownXMLObjects.subList(typeOrName); + } + + /** {@inheritDoc} */ + public List getOrderedChildren() { + return Collections.unmodifiableList(unknownXMLObjects); + } + + /** {@inheritDoc} */ + public AttributeMap getUnknownAttributes() { + return unknownAttributes; + } +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/schema/impl/XSAnyMarshaller.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/schema/impl/XSAnyMarshaller.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/schema/impl/XSAnyMarshaller.java 17 Aug 2012 15:17:09 -0000 1.1 @@ -0,0 +1,62 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.schema.impl; + +import java.util.Map.Entry; + +import javax.xml.namespace.QName; + +import org.opensaml.xml.Configuration; +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.io.AbstractXMLObjectMarshaller; +import org.opensaml.xml.io.MarshallingException; +import org.opensaml.xml.schema.XSAny; +import org.opensaml.xml.util.XMLHelper; +import org.w3c.dom.Attr; +import org.w3c.dom.Element; + +/** + * Thread-safe marshaller of {@link XSAny} objects. + */ +public class XSAnyMarshaller extends AbstractXMLObjectMarshaller { + + /** {@inheritDoc} */ + protected void marshallAttributes(XMLObject xmlObject, Element domElement) throws MarshallingException { + XSAny xsAny = (XSAny) xmlObject; + + Attr attribute; + for (Entry entry : xsAny.getUnknownAttributes().entrySet()) { + attribute = XMLHelper.constructAttribute(domElement.getOwnerDocument(), entry.getKey()); + attribute.setValue(entry.getValue()); + domElement.setAttributeNodeNS(attribute); + if (Configuration.isIDAttribute(entry.getKey()) + || xsAny.getUnknownAttributes().isIDAttribute(entry.getKey())) { + attribute.getOwnerElement().setIdAttributeNode(attribute, true); + } + } + } + + /** {@inheritDoc} */ + protected void marshallElementContent(XMLObject xmlObject, Element domElement) throws MarshallingException { + XSAny xsAny = (XSAny) xmlObject; + + if (xsAny.getTextContent() != null) { + XMLHelper.appendTextContent(domElement, xsAny.getTextContent()); + } + } +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/schema/impl/XSAnyUnmarshaller.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/schema/impl/XSAnyUnmarshaller.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/schema/impl/XSAnyUnmarshaller.java 17 Aug 2012 15:17:10 -0000 1.1 @@ -0,0 +1,62 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.schema.impl; + +import javax.xml.namespace.QName; + +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.io.AbstractXMLObjectUnmarshaller; +import org.opensaml.xml.io.UnmarshallingException; +import org.opensaml.xml.schema.XSAny; +import org.opensaml.xml.util.XMLHelper; +import org.w3c.dom.Attr; + +/** + * A thread-safe unmarshaller for {@link XSAny}s. + */ +public class XSAnyUnmarshaller extends AbstractXMLObjectUnmarshaller { + + /** {@inheritDoc} */ + protected void processChildElement(XMLObject parentXMLObject, XMLObject childXMLObject) + throws UnmarshallingException { + XSAny xsAny = (XSAny) parentXMLObject; + + xsAny.getUnknownXMLObjects().add(childXMLObject); + } + + /** {@inheritDoc} */ + protected void processAttribute(XMLObject xmlObject, Attr attribute) throws UnmarshallingException { + XSAny xsAny = (XSAny) xmlObject; + + QName attribQName = XMLHelper.constructQName(attribute.getNamespaceURI(), attribute.getLocalName(), attribute + .getPrefix()); + + if (attribute.isId()) { + xsAny.getUnknownAttributes().registerID(attribQName); + } + + xsAny.getUnknownAttributes().put(attribQName, attribute.getValue()); + } + + /** {@inheritDoc} */ + protected void processElementContent(XMLObject xmlObject, String elementContent) { + XSAny xsAny = (XSAny) xmlObject; + + xsAny.setTextContent(elementContent); + } +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/schema/impl/XSBase64BinaryBuilder.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/schema/impl/XSBase64BinaryBuilder.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/schema/impl/XSBase64BinaryBuilder.java 17 Aug 2012 15:17:09 -0000 1.1 @@ -0,0 +1,32 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.schema.impl; + +import org.opensaml.xml.AbstractXMLObjectBuilder; +import org.opensaml.xml.schema.XSBase64Binary; + +/** + * Builder of {@link org.opensaml.xml.schema.impl.XSBase64BinaryImpl} objects. + */ +public class XSBase64BinaryBuilder extends AbstractXMLObjectBuilder { + + /** {@inheritDoc} */ + public XSBase64Binary buildObject(String namespaceURI, String localName, String namespacePrefix) { + return new XSBase64BinaryImpl(namespaceURI, localName, namespacePrefix); + } +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/schema/impl/XSBase64BinaryImpl.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/schema/impl/XSBase64BinaryImpl.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/schema/impl/XSBase64BinaryImpl.java 17 Aug 2012 15:17:09 -0000 1.1 @@ -0,0 +1,66 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.schema.impl; + +import java.util.List; + +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.schema.XSBase64Binary; +import org.opensaml.xml.validation.AbstractValidatingXMLObject; + +/** + * Concrete implementation of {@link org.opensaml.xml.schema.XSBase64Binary}. + */ +public class XSBase64BinaryImpl extends AbstractValidatingXMLObject implements XSBase64Binary { + + /** Value of this base64Binary element. */ + private String value; + + /** + * Constructor. + * + * @param namespaceURI the namespace the element is in + * @param elementLocalName the local name of the XML element this Object represents + * @param namespacePrefix the prefix for the given namespace + */ + protected XSBase64BinaryImpl(String namespaceURI, String elementLocalName, String namespacePrefix) { + super(namespaceURI, elementLocalName, namespacePrefix); + } + + /** + * {@inheritDoc} + */ + public String getValue() { + return value; + } + + /** + * {@inheritDoc} + */ + public void setValue(String newValue) { + value = prepareForAssignment(value, newValue); + } + + /** + * {@inheritDoc} + */ + public List getOrderedChildren() { + // no children + return null; + } +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/schema/impl/XSBase64BinaryMarshaller.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/schema/impl/XSBase64BinaryMarshaller.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/schema/impl/XSBase64BinaryMarshaller.java 17 Aug 2012 15:17:09 -0000 1.1 @@ -0,0 +1,43 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.schema.impl; + +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.io.AbstractXMLObjectMarshaller; +import org.opensaml.xml.io.MarshallingException; +import org.opensaml.xml.schema.XSBase64Binary; +import org.opensaml.xml.util.XMLHelper; +import org.w3c.dom.Element; + +/** + * Thread-safe marshaller of {@link org.opensaml.xml.schema.XSBase64Binary} objects. + */ +public class XSBase64BinaryMarshaller extends AbstractXMLObjectMarshaller { + + /** {@inheritDoc} */ + protected void marshallAttributes(XMLObject xmlObject, Element domElement) throws MarshallingException { + // no attributes + } + + /** {@inheritDoc} */ + protected void marshallElementContent(XMLObject xmlObject, Element domElement) throws MarshallingException { + XSBase64Binary xsBase64Binary = (XSBase64Binary) xmlObject; + + XMLHelper.appendTextContent(domElement, xsBase64Binary.getValue()); + } +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/schema/impl/XSBase64BinaryUnmarshaller.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/schema/impl/XSBase64BinaryUnmarshaller.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/schema/impl/XSBase64BinaryUnmarshaller.java 17 Aug 2012 15:17:09 -0000 1.1 @@ -0,0 +1,50 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.schema.impl; + +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.io.AbstractXMLObjectUnmarshaller; +import org.opensaml.xml.io.UnmarshallingException; +import org.opensaml.xml.schema.XSBase64Binary; +import org.w3c.dom.Attr; + +/** + * Thread-safe unmarshaller for {@link org.opensaml.xml.schema.XSBase64Binary} objects. + */ +public class XSBase64BinaryUnmarshaller extends AbstractXMLObjectUnmarshaller { + + /** {@inheritDoc} */ + protected void processChildElement(XMLObject parentXMLObject, XMLObject childXMLObject) + throws UnmarshallingException { + // no children + } + + /** {@inheritDoc} */ + protected void processAttribute(XMLObject xmlObject, Attr attribute) throws UnmarshallingException { + // no attributes + } + + /** {@inheritDoc} */ + protected void processElementContent(XMLObject xmlObject, String elementContent) { + XSBase64Binary xsBase64Binary = (XSBase64Binary) xmlObject; + + if (elementContent != null) { + xsBase64Binary.setValue(elementContent.trim()); + } + } +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/schema/impl/XSDateTimeBuilder.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/schema/impl/XSDateTimeBuilder.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/schema/impl/XSDateTimeBuilder.java 17 Aug 2012 15:17:09 -0000 1.1 @@ -0,0 +1,33 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.schema.impl; + +import org.opensaml.xml.AbstractXMLObjectBuilder; +import org.opensaml.xml.schema.XSDateTime; + +/** + * Builder of {@link org.opensaml.xml.schema.XSDateTime} objects. + */ +public class XSDateTimeBuilder extends AbstractXMLObjectBuilder { + + /** {@inheritDoc} */ + public XSDateTime buildObject(String namespaceURI, String localName, String namespacePrefix) { + return new XSDateTimeImpl(namespaceURI, localName, namespacePrefix); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/schema/impl/XSDateTimeImpl.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/schema/impl/XSDateTimeImpl.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/schema/impl/XSDateTimeImpl.java 17 Aug 2012 15:17:09 -0000 1.1 @@ -0,0 +1,83 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.schema.impl; + +import java.util.Collections; +import java.util.List; + +import org.joda.time.DateTime; +import org.joda.time.chrono.ISOChronology; +import org.joda.time.format.DateTimeFormatter; +import org.joda.time.format.ISODateTimeFormat; +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.schema.XSDateTime; +import org.opensaml.xml.validation.AbstractValidatingXMLObject; + + +/** + * Concrete implementation of {@link org.opensaml.xml.schema.XSDateTime}. + */ +public class XSDateTimeImpl extends AbstractValidatingXMLObject implements XSDateTime { + + /** Value of this dateTime element. */ + private DateTime value; + + /** The date time formatter to use. */ + private DateTimeFormatter formatter; + + /** + * Constructor. + * + * @param namespaceURI the namespace the element is in + * @param elementLocalName the local name of the XML element this Object represents + * @param namespacePrefix the prefix for the given namespace + */ + protected XSDateTimeImpl(String namespaceURI, String elementLocalName, String namespacePrefix) { + super(namespaceURI, elementLocalName, namespacePrefix); + formatter = ISODateTimeFormat.dateTime().withChronology(ISOChronology.getInstanceUTC()); + } + + /** {@inheritDoc} */ + public DateTime getValue() { + return value; + } + + /** {@inheritDoc} */ + public void setValue(DateTime newValue) { + value = prepareForAssignment(value, newValue); + } + + /** {@inheritDoc} */ + public List getOrderedChildren() { + return Collections.emptyList(); + } + + /** {@inheritDoc} */ + public DateTimeFormatter getDateTimeFormatter() { + return formatter; + } + + /** {@inheritDoc} */ + public void setDateTimeFormatter(DateTimeFormatter newFormatter) { + if (newFormatter == null) { + throw new IllegalArgumentException("The specified DateTimeFormatter may not be null"); + } + formatter = newFormatter; + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/schema/impl/XSDateTimeMarshaller.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/schema/impl/XSDateTimeMarshaller.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/schema/impl/XSDateTimeMarshaller.java 17 Aug 2012 15:17:09 -0000 1.1 @@ -0,0 +1,42 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.schema.impl; + +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.io.BaseXMLObjectMarshaller; +import org.opensaml.xml.io.MarshallingException; +import org.opensaml.xml.schema.XSDateTime; +import org.opensaml.xml.util.XMLHelper; +import org.w3c.dom.Element; + +/** + * Thread-safe marshaller of {@link org.opensaml.xml.schema.XSDateTime} objects. + */ +public class XSDateTimeMarshaller extends BaseXMLObjectMarshaller { + + /** Constructor. */ + public XSDateTimeMarshaller(){} + + /** {@inheritDoc} */ + protected void marshallElementContent(XMLObject xmlObject, Element domElement) throws MarshallingException { + XSDateTime xsDateTime = (XSDateTime) xmlObject; + + XMLHelper.appendTextContent(domElement, xsDateTime.getDateTimeFormatter().print(xsDateTime.getValue())); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/schema/impl/XSDateTimeUnmarshaller.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/schema/impl/XSDateTimeUnmarshaller.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/schema/impl/XSDateTimeUnmarshaller.java 17 Aug 2012 15:17:09 -0000 1.1 @@ -0,0 +1,41 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.schema.impl; + +import org.joda.time.DateTime; +import org.joda.time.chrono.ISOChronology; +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.io.BaseXMLObjectUnmarshaller; +import org.opensaml.xml.schema.XSDateTime; + +/** + * Thread-safe unmarshaller for {@link org.opensaml.xml.schema.XSDateTime} objects. + */ +public class XSDateTimeUnmarshaller extends BaseXMLObjectUnmarshaller{ + + /** Constructor. */ + public XSDateTimeUnmarshaller(){} + + /** {@inheritDoc} */ + protected void processElementContent(XMLObject xmlObject, String elementContent) { + XSDateTime xsDateTime = (XSDateTime) xmlObject; + + xsDateTime.setValue(new DateTime(elementContent).withChronology(ISOChronology.getInstanceUTC())); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/schema/impl/XSIntegerBuilder.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/schema/impl/XSIntegerBuilder.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/schema/impl/XSIntegerBuilder.java 17 Aug 2012 15:17:09 -0000 1.1 @@ -0,0 +1,32 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.schema.impl; + +import org.opensaml.xml.AbstractXMLObjectBuilder; +import org.opensaml.xml.schema.XSInteger; + +/** + * Builder of {@link org.opensaml.xml.schema.impl.XSIntegerImpl} objects. + */ +public class XSIntegerBuilder extends AbstractXMLObjectBuilder { + + /** {@inheritDoc} */ + public XSInteger buildObject(String namespaceURI, String localName, String namespacePrefix) { + return new XSIntegerImpl(namespaceURI, localName, namespacePrefix); + } +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/schema/impl/XSIntegerImpl.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/schema/impl/XSIntegerImpl.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/schema/impl/XSIntegerImpl.java 17 Aug 2012 15:17:10 -0000 1.1 @@ -0,0 +1,66 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.schema.impl; + +import java.util.List; + +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.schema.XSInteger; +import org.opensaml.xml.validation.AbstractValidatingXMLObject; + +/** + * Concrete implementation of {@link org.opensaml.xml.schema.XSInteger}. + */ +public class XSIntegerImpl extends AbstractValidatingXMLObject implements XSInteger { + + /** Value of this integer element. */ + private Integer value; + + /** + * Constructor. + * + * @param namespaceURI the namespace the element is in + * @param elementLocalName the local name of the XML element this Object represents + * @param namespacePrefix the prefix for the given namespace + */ + protected XSIntegerImpl(String namespaceURI, String elementLocalName, String namespacePrefix) { + super(namespaceURI, elementLocalName, namespacePrefix); + } + + /** + * {@inheritDoc} + */ + public Integer getValue() { + return value; + } + + /** + * {@inheritDoc} + */ + public void setValue(Integer newValue) { + value = prepareForAssignment(value, newValue); + } + + /** + * {@inheritDoc} + */ + public List getOrderedChildren() { + // no children + return null; + } +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/schema/impl/XSIntegerMarshaller.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/schema/impl/XSIntegerMarshaller.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/schema/impl/XSIntegerMarshaller.java 17 Aug 2012 15:17:09 -0000 1.1 @@ -0,0 +1,45 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.schema.impl; + +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.io.AbstractXMLObjectMarshaller; +import org.opensaml.xml.io.MarshallingException; +import org.opensaml.xml.schema.XSInteger; +import org.opensaml.xml.util.XMLHelper; +import org.w3c.dom.Element; + +/** + * Thread-safe marshaller of {@link org.opensaml.xml.schema.XSInteger} objects. + */ +public class XSIntegerMarshaller extends AbstractXMLObjectMarshaller { + + /** {@inheritDoc} */ + protected void marshallAttributes(XMLObject xmlObject, Element domElement) throws MarshallingException { + // no attributes + } + + /** {@inheritDoc} */ + protected void marshallElementContent(XMLObject xmlObject, Element domElement) throws MarshallingException { + XSInteger xsiInteger = (XSInteger) xmlObject; + + if (xsiInteger.getValue() != null) { + XMLHelper.appendTextContent(domElement, xsiInteger.getValue().toString()); + } + } +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/schema/impl/XSIntegerUnmarshaller.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/schema/impl/XSIntegerUnmarshaller.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/schema/impl/XSIntegerUnmarshaller.java 17 Aug 2012 15:17:10 -0000 1.1 @@ -0,0 +1,50 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.schema.impl; + +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.io.AbstractXMLObjectUnmarshaller; +import org.opensaml.xml.io.UnmarshallingException; +import org.opensaml.xml.schema.XSInteger; +import org.w3c.dom.Attr; + +/** + * Thread-safe unmarshaller for {@link org.opensaml.xml.schema.XSInteger} objects. + */ +public class XSIntegerUnmarshaller extends AbstractXMLObjectUnmarshaller { + + /** {@inheritDoc} */ + protected void processChildElement(XMLObject parentXMLObject, XMLObject childXMLObject) + throws UnmarshallingException { + // no children + } + + /** {@inheritDoc} */ + protected void processAttribute(XMLObject xmlObject, Attr attribute) throws UnmarshallingException { + // no attributes + } + + /** {@inheritDoc} */ + protected void processElementContent(XMLObject xmlObject, String elementContent) { + XSInteger xsiInteger = (XSInteger) xmlObject; + + if (elementContent != null) { + xsiInteger.setValue(Integer.valueOf(elementContent.trim())); + } + } +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/schema/impl/XSQNameBuilder.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/schema/impl/XSQNameBuilder.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/schema/impl/XSQNameBuilder.java 17 Aug 2012 15:17:09 -0000 1.1 @@ -0,0 +1,32 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.schema.impl; + +import org.opensaml.xml.AbstractXMLObjectBuilder; +import org.opensaml.xml.schema.XSQName; + +/** + * Builder of {@link org.opensaml.xml.schema.impl.XSQNameImpl} objects. + */ +public class XSQNameBuilder extends AbstractXMLObjectBuilder { + + /** {@inheritDoc} */ + public XSQName buildObject(String namespaceURI, String localName, String namespacePrefix) { + return new XSQNameImpl(namespaceURI, localName, namespacePrefix); + } +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/schema/impl/XSQNameImpl.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/schema/impl/XSQNameImpl.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/schema/impl/XSQNameImpl.java 17 Aug 2012 15:17:09 -0000 1.1 @@ -0,0 +1,63 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.schema.impl; + +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; + +import javax.xml.namespace.QName; + +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.schema.XSQName; +import org.opensaml.xml.validation.AbstractValidatingXMLObject; + +/** + * Concrete implementation of {@link org.opensaml.xml.schema.XSQName}. + */ +public class XSQNameImpl extends AbstractValidatingXMLObject implements XSQName { + + /** QName value. */ + private QName value; + + /** + * Constructor. + * + * @param namespaceURI the namespace the element is in + * @param elementLocalName the local name of the XML element this Object represents + * @param namespacePrefix the prefix for the given namespace + */ + protected XSQNameImpl(String namespaceURI, String elementLocalName, String namespacePrefix) { + super(namespaceURI, elementLocalName, namespacePrefix); + } + + /** {@inheritDoc} */ + public QName getValue() { + return value; + } + + /** {@inheritDoc} */ + public void setValue(QName newValue) { + value = prepareElementContentForAssignment(value, newValue); + } + + /** {@inheritDoc} */ + public List getOrderedChildren() { + return Collections.unmodifiableList(new LinkedList()); + } +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/schema/impl/XSQNameMarshaller.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/schema/impl/XSQNameMarshaller.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/schema/impl/XSQNameMarshaller.java 17 Aug 2012 15:17:10 -0000 1.1 @@ -0,0 +1,42 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.schema.impl; + +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.io.AbstractXMLObjectMarshaller; +import org.opensaml.xml.io.MarshallingException; +import org.opensaml.xml.schema.XSQName; +import org.opensaml.xml.util.XMLHelper; +import org.w3c.dom.Element; + +/** + * A thread-safe marshaller for {@link org.opensaml.xml.schema.XSQName}s. + */ +public class XSQNameMarshaller extends AbstractXMLObjectMarshaller { + + /** {@inheritDoc} */ + protected void marshallAttributes(XMLObject xmlObject, Element domElement) throws MarshallingException { + // no attributes to marshall + } + + /** {@inheritDoc} */ + protected void marshallElementContent(XMLObject xmlObject, Element domElement) throws MarshallingException { + XSQName qname = (XSQName) xmlObject; + XMLHelper.appendTextContent(domElement, XMLHelper.qnameToContentString(qname.getValue())); + } +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/schema/impl/XSQNameUnmarshaller.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/schema/impl/XSQNameUnmarshaller.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/schema/impl/XSQNameUnmarshaller.java 17 Aug 2012 15:17:09 -0000 1.1 @@ -0,0 +1,58 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.schema.impl; + +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.io.AbstractXMLObjectUnmarshaller; +import org.opensaml.xml.io.UnmarshallingException; +import org.opensaml.xml.schema.XSQName; +import org.opensaml.xml.util.DatatypeHelper; +import org.opensaml.xml.util.XMLHelper; +import org.w3c.dom.Attr; +import org.w3c.dom.Text; + +/** + * A thread-safe unmarshaller for {@link org.opensaml.xml.schema.XSQName}s. + */ +public class XSQNameUnmarshaller extends AbstractXMLObjectUnmarshaller { + + /** {@inheritDoc} */ + protected void processChildElement(XMLObject parentXMLObject, XMLObject childXMLObject) + throws UnmarshallingException { + // no child elements + } + + /** {@inheritDoc} */ + protected void processAttribute(XMLObject xmlObject, Attr attribute) throws UnmarshallingException { + // no attributes + } + + /** {@inheritDoc} */ + protected void processElementContent(XMLObject xmlObject, String elementContent) { + // handled by overriden unmarshallTextContent() directly, because we need access to the owning DOM element + } + + /** {@inheritDoc} */ + protected void unmarshallTextContent(XMLObject xmlObject, Text content) throws UnmarshallingException { + String textContent = DatatypeHelper.safeTrimOrNullString(content.getWholeText()); + if (textContent != null) { + XSQName qname = (XSQName) xmlObject; + qname.setValue(XMLHelper.constructQName(textContent, XMLHelper.getElementAncestor(content))); + } + } +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/schema/impl/XSStringBuilder.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/schema/impl/XSStringBuilder.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/schema/impl/XSStringBuilder.java 17 Aug 2012 15:17:10 -0000 1.1 @@ -0,0 +1,32 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.schema.impl; + +import org.opensaml.xml.AbstractXMLObjectBuilder; +import org.opensaml.xml.schema.XSString; + +/** + * Builder of {@link org.opensaml.xml.schema.impl.XSStringImpl} objects. + */ +public class XSStringBuilder extends AbstractXMLObjectBuilder { + + /** {@inheritDoc} */ + public XSString buildObject(String namespaceURI, String localName, String namespacePrefix) { + return new XSStringImpl(namespaceURI, localName, namespacePrefix); + } +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/schema/impl/XSStringImpl.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/schema/impl/XSStringImpl.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/schema/impl/XSStringImpl.java 17 Aug 2012 15:17:10 -0000 1.1 @@ -0,0 +1,66 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.schema.impl; + +import java.util.List; + +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.schema.XSString; +import org.opensaml.xml.validation.AbstractValidatingXMLObject; + +/** + * Concrete implementation of {@link org.opensaml.xml.schema.XSString}. + */ +public class XSStringImpl extends AbstractValidatingXMLObject implements XSString { + + /** Value of this string element. */ + private String value; + + /** + * Constructor. + * + * @param namespaceURI the namespace the element is in + * @param elementLocalName the local name of the XML element this Object represents + * @param namespacePrefix the prefix for the given namespace + */ + protected XSStringImpl(String namespaceURI, String elementLocalName, String namespacePrefix) { + super(namespaceURI, elementLocalName, namespacePrefix); + } + + /** + * {@inheritDoc} + */ + public String getValue() { + return value; + } + + /** + * {@inheritDoc} + */ + public void setValue(String newValue) { + value = prepareForAssignment(value, newValue); + } + + /** + * {@inheritDoc} + */ + public List getOrderedChildren() { + // no children + return null; + } +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/schema/impl/XSStringMarshaller.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/schema/impl/XSStringMarshaller.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/schema/impl/XSStringMarshaller.java 17 Aug 2012 15:17:09 -0000 1.1 @@ -0,0 +1,43 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.schema.impl; + +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.io.AbstractXMLObjectMarshaller; +import org.opensaml.xml.io.MarshallingException; +import org.opensaml.xml.schema.XSString; +import org.opensaml.xml.util.XMLHelper; +import org.w3c.dom.Element; + +/** + * Thread-safe marshaller of {@link org.opensaml.xml.schema.XSString} objects. + */ +public class XSStringMarshaller extends AbstractXMLObjectMarshaller { + + /** {@inheritDoc} */ + protected void marshallAttributes(XMLObject xmlObject, Element domElement) throws MarshallingException { + // no attributes + } + + /** {@inheritDoc} */ + protected void marshallElementContent(XMLObject xmlObject, Element domElement) throws MarshallingException { + XSString xsiString = (XSString) xmlObject; + + XMLHelper.appendTextContent(domElement, xsiString.getValue()); + } +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/schema/impl/XSStringUnmarshaller.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/schema/impl/XSStringUnmarshaller.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/schema/impl/XSStringUnmarshaller.java 17 Aug 2012 15:17:09 -0000 1.1 @@ -0,0 +1,48 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.schema.impl; + +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.io.AbstractXMLObjectUnmarshaller; +import org.opensaml.xml.io.UnmarshallingException; +import org.opensaml.xml.schema.XSString; +import org.w3c.dom.Attr; + +/** + * Thread-safe unmarshaller for {@link org.opensaml.xml.schema.XSString} objects. + */ +public class XSStringUnmarshaller extends AbstractXMLObjectUnmarshaller { + + /** {@inheritDoc} */ + protected void processChildElement(XMLObject parentXMLObject, XMLObject childXMLObject) + throws UnmarshallingException { + // no children + } + + /** {@inheritDoc} */ + protected void processAttribute(XMLObject xmlObject, Attr attribute) throws UnmarshallingException { + // no attributes + } + + /** {@inheritDoc} */ + protected void processElementContent(XMLObject xmlObject, String elementContent) { + XSString xsiString = (XSString) xmlObject; + + xsiString.setValue(elementContent); + } +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/schema/impl/XSURIBuilder.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/schema/impl/XSURIBuilder.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/schema/impl/XSURIBuilder.java 17 Aug 2012 15:17:09 -0000 1.1 @@ -0,0 +1,32 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.schema.impl; + +import org.opensaml.xml.AbstractXMLObjectBuilder; +import org.opensaml.xml.schema.XSURI; + +/** + * Builder of {@link org.opensaml.xml.schema.impl.XSURIImpl} objects. + */ +public class XSURIBuilder extends AbstractXMLObjectBuilder { + + /** {@inheritDoc} */ + public XSURI buildObject(String namespaceURI, String localName, String namespacePrefix) { + return new XSURIImpl(namespaceURI, localName, namespacePrefix); + } +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/schema/impl/XSURIImpl.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/schema/impl/XSURIImpl.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/schema/impl/XSURIImpl.java 17 Aug 2012 15:17:09 -0000 1.1 @@ -0,0 +1,61 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.schema.impl; + +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; + +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.schema.XSURI; +import org.opensaml.xml.validation.AbstractValidatingXMLObject; + +/** + * Conrete implementation of {@link org.opensaml.xml.schema.XSURI}. + */ +public class XSURIImpl extends AbstractValidatingXMLObject implements XSURI { + + /** URI value. */ + private String value; + + /** + * Constructor. + * + * @param namespaceURI the namespace the element is in + * @param elementLocalName the local name of the XML element this Object represents + * @param namespacePrefix the prefix for the given namespace + */ + protected XSURIImpl(String namespaceURI, String elementLocalName, String namespacePrefix) { + super(namespaceURI, elementLocalName, namespacePrefix); + } + + /** {@inheritDoc} */ + public String getValue() { + return value; + } + + /** {@inheritDoc} */ + public void setValue(String newValue) { + value = prepareForAssignment(value, newValue); + } + + /** {@inheritDoc} */ + public List getOrderedChildren() { + return Collections.unmodifiableList(new LinkedList()); + } +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/schema/impl/XSURIMarshaller.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/schema/impl/XSURIMarshaller.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/schema/impl/XSURIMarshaller.java 17 Aug 2012 15:17:10 -0000 1.1 @@ -0,0 +1,43 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.schema.impl; + +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.io.AbstractXMLObjectMarshaller; +import org.opensaml.xml.io.MarshallingException; +import org.opensaml.xml.schema.XSURI; +import org.opensaml.xml.util.XMLHelper; +import org.w3c.dom.Element; + +/** + * A thread-safe marshaller for {@link org.opensaml.xml.schema.XSURI}s. + */ +public class XSURIMarshaller extends AbstractXMLObjectMarshaller { + + /** {@inheritDoc} */ + protected void marshallAttributes(XMLObject xmlObject, Element domElement) throws MarshallingException { + // no attributes + } + + /** {@inheritDoc} */ + protected void marshallElementContent(XMLObject xmlObject, Element domElement) throws MarshallingException { + XSURI uri = (XSURI) xmlObject; + + XMLHelper.appendTextContent(domElement, uri.getValue()); + } +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/schema/impl/XSURIUnmarshaller.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/schema/impl/XSURIUnmarshaller.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/schema/impl/XSURIUnmarshaller.java 17 Aug 2012 15:17:09 -0000 1.1 @@ -0,0 +1,47 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.schema.impl; + +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.io.AbstractXMLObjectUnmarshaller; +import org.opensaml.xml.io.UnmarshallingException; +import org.opensaml.xml.schema.XSURI; +import org.w3c.dom.Attr; + +/** + * A thread-safe unmarshaller for {@link org.opensaml.xml.schema.XSURI}s. + */ +public class XSURIUnmarshaller extends AbstractXMLObjectUnmarshaller { + + /** {@inheritDoc} */ + protected void processChildElement(XMLObject parentXMLObject, XMLObject childXMLObject) + throws UnmarshallingException { + // no child elements + } + + /** {@inheritDoc} */ + protected void processAttribute(XMLObject xmlObject, Attr attribute) throws UnmarshallingException { + // no attributes + } + + /** {@inheritDoc} */ + protected void processElementContent(XMLObject xmlObject, String elementContent) { + XSURI uri = (XSURI) xmlObject; + uri.setValue(elementContent); + } +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/schema/impl/package.html =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/schema/impl/package.html,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/schema/impl/package.html 17 Aug 2012 15:17:09 -0000 1.1 @@ -0,0 +1,6 @@ + + +Implementations of the interfaces for XMLObjects that represent XML schema types. + + + \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/schema/validator/XSBase64BinarySchemaValidator.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/schema/validator/XSBase64BinarySchemaValidator.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/schema/validator/XSBase64BinarySchemaValidator.java 17 Aug 2012 15:17:16 -0000 1.1 @@ -0,0 +1,82 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.schema.validator; + +import org.opensaml.xml.schema.XSBase64Binary; +import org.opensaml.xml.util.DatatypeHelper; +import org.opensaml.xml.validation.ValidationException; +import org.opensaml.xml.validation.Validator; + +/** + * Checks {@link org.opensaml.xml.schema.XSBase64Binary} for Schema compliance. + * + * @param the type to be validated + */ +public class XSBase64BinarySchemaValidator implements Validator { + + /** Flag specifying whether empty element content should be allowed. */ + private boolean allowEmptyContent; + + /** + * Constructor. + * + * @param allowEmptyElementContent flag indicated whether empty content should be allowed + */ + public XSBase64BinarySchemaValidator(boolean allowEmptyElementContent) { + allowEmptyContent = allowEmptyElementContent; + } + + /** + * Constructor. + * + * Empty content is not allowed. + * + */ + public XSBase64BinarySchemaValidator() { + allowEmptyContent = false; + } + + /** {@inheritDoc} */ + public void validate(T xmlObject) throws ValidationException { + validateBase64BinaryContent(xmlObject); + } + + /** + * Get the flag which determines whether empty content should be allowed. + * + * @return true if empty content should be allowed, false otherwise + */ + protected boolean isAllowEmptyContent() { + return allowEmptyContent; + } + + /** + * Validates the content of the XSBase64Binary object. + * + * @param xmlObject the object to evaluate + * @throws ValidationException thrown if the content of the Base64Binary object is invalid + */ + protected void validateBase64BinaryContent(T xmlObject) throws ValidationException { + if (! isAllowEmptyContent()) { + if (DatatypeHelper.isEmpty(xmlObject.getValue())) { + throw new ValidationException("Base64Binary content may not be empty"); + } + } + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/schema/validator/XSDateTimeSchemaValidator.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/schema/validator/XSDateTimeSchemaValidator.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/schema/validator/XSDateTimeSchemaValidator.java 17 Aug 2012 15:17:16 -0000 1.1 @@ -0,0 +1,73 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.schema.validator; + +import org.opensaml.xml.schema.XSDateTime; +import org.opensaml.xml.validation.ValidationException; +import org.opensaml.xml.validation.Validator; + +/** + * Checks {@link org.opensaml.xml.schema.XSDateTime} for Schema compliance. + * + * @param the type to be validated + */ +public class XSDateTimeSchemaValidator implements Validator { + /** Flag specifying whether empty element content should be allowed. */ + private boolean allowEmptyContent; + + /** + * Constructor. + * + * @param allowEmptyContent flag indicated whether empty content should be allowed + */ + public XSDateTimeSchemaValidator(boolean allowEmptyContent) { + this.allowEmptyContent = allowEmptyContent; + } + + /** Constructor. */ + public XSDateTimeSchemaValidator(){ + allowEmptyContent = false; + } + + /** + * Get the flag which determines whether empty content should be allowed. + * + * @return true if empty content should be allowed, false otherwise + */ + protected boolean isAllowEmptyContent() { + return allowEmptyContent; + } + + /** {@inheritDoc} */ + public void validate(T xmlObject) throws ValidationException { + validateDateTimeContent(xmlObject); + } + + /** + * Validates the content of the XSDateTime object. + * + * @param xmlObject the object to evaluate + * @throws ValidationException thrown if the content of the object is invalid + */ + protected void validateDateTimeContent(T xmlObject) throws ValidationException{ + if(!allowEmptyContent && xmlObject.getValue() == null){ + throw new ValidationException("dateTime content may not be empty"); + } + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/schema/validator/XSIntegerSchemaValidator.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/schema/validator/XSIntegerSchemaValidator.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/schema/validator/XSIntegerSchemaValidator.java 17 Aug 2012 15:17:16 -0000 1.1 @@ -0,0 +1,81 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.schema.validator; + +import org.opensaml.xml.schema.XSInteger; +import org.opensaml.xml.validation.ValidationException; +import org.opensaml.xml.validation.Validator; + +/** + * Checks {@link org.opensaml.xml.schema.XSInteger} for Schema compliance. + * + * @param the type to be validated + */ +public class XSIntegerSchemaValidator implements Validator { + + /** Flag specifying whether empty element content should be allowed. */ + private boolean allowEmptyContent; + + /** + * Constructor. + * + * @param allowEmptyElementContent flag indicated whether empty content should be allowed + */ + public XSIntegerSchemaValidator(boolean allowEmptyElementContent) { + allowEmptyContent = allowEmptyElementContent; + } + + /** + * Constructor. + * + * Empty content is not allowed. + * + */ + public XSIntegerSchemaValidator() { + allowEmptyContent = false; + } + + /** {@inheritDoc} */ + public void validate(T xmlObject) throws ValidationException { + validateIntegerContent(xmlObject); + } + + /** + * Get the flag which determines whether empty content should be allowed. + * + * @return true if empty content should be allowed, false otherwise + */ + protected boolean isAllowEmptyContent() { + return allowEmptyContent; + } + + /** + * Validates the content of the XSBase64Binary object. + * + * @param xmlObject the object to evaluate + * @throws ValidationException thrown if the content of the Base64Binary object is invalid + */ + protected void validateIntegerContent(T xmlObject) throws ValidationException { + if (! isAllowEmptyContent()) { + if (xmlObject.getValue() == null) { + throw new ValidationException("Integer content may not be empty"); + } + } + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/schema/validator/XSStringSchemaValidator.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/schema/validator/XSStringSchemaValidator.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/schema/validator/XSStringSchemaValidator.java 17 Aug 2012 15:17:16 -0000 1.1 @@ -0,0 +1,82 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.schema.validator; + +import org.opensaml.xml.schema.XSString; +import org.opensaml.xml.util.DatatypeHelper; +import org.opensaml.xml.validation.ValidationException; +import org.opensaml.xml.validation.Validator; + +/** + * Checks {@link org.opensaml.xml.schema.XSString} for Schema compliance. + * + * @param the type to be validated + */ +public class XSStringSchemaValidator implements Validator { + + /** Flag specifying whether empty element content should be allowed. */ + private boolean allowEmptyContent; + + /** + * Constructor. + * + * @param allowEmptyElementContent flag indicated whether empty content should be allowed + */ + public XSStringSchemaValidator(boolean allowEmptyElementContent) { + allowEmptyContent = allowEmptyElementContent; + } + + /** + * Constructor. + * + * Empty content is not allowed. + * + */ + public XSStringSchemaValidator() { + allowEmptyContent = false; + } + + /** {@inheritDoc} */ + public void validate(T xmlObject) throws ValidationException { + validateStringContent(xmlObject); + } + + /** + * Get the flag which determines whether empty content should be allowed. + * + * @return true if empty content should be allowed, false otherwise + */ + protected boolean isAllowEmptyContent() { + return allowEmptyContent; + } + + /** + * Validates the content of the XSBase64Binary object. + * + * @param xmlObject the object to evaluate + * @throws ValidationException thrown if the content of the Base64Binary object is invalid + */ + protected void validateStringContent(T xmlObject) throws ValidationException { + if (! isAllowEmptyContent()) { + if (DatatypeHelper.isEmpty(xmlObject.getValue())) { + throw new ValidationException("String content may not be empty"); + } + } + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/security/ApacheXMLSecurityConstants.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/security/ApacheXMLSecurityConstants.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/security/ApacheXMLSecurityConstants.java 17 Aug 2012 15:17:18 -0000 1.1 @@ -0,0 +1,46 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.security; + +/** + * Constants used within the Apache XML Security library. + */ +public class ApacheXMLSecurityConstants { + + /** Block encryption algorithm class. */ + public static final String ALGO_CLASS_BLOCK_ENCRYPTION = "BlockEncryption"; + + /** Key transport algorithm class. */ + public static final String ALGO_CLASS_KEY_TRANSPORT = "KeyTransport"; + + /** Key agreement algorithm class. */ + public static final String ALGO_CLASS_KEY_AGREEMENT = "KeyAgreement"; + + /** HMAC algorithm class. */ + public static final String ALGO_CLASS_MAC = "Mac"; + + /** Message digest algorithm class. */ + public static final String ALGO_CLASS_MESSAGE_DIGEST = "MessageDigest"; + + /** Signature algorithm class. */ + public static final String ALGO_CLASS_SIGNATURE = "Signature"; + + /** Symmetric key wrap algorithm class. */ + public static final String ALGO_CLASS_SYMMETRIC_KEY_WRAP = "SymmetricKeyWrap"; + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/security/BasicSecurityConfiguration.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/security/BasicSecurityConfiguration.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/security/BasicSecurityConfiguration.java 17 Aug 2012 15:17:19 -0000 1.1 @@ -0,0 +1,534 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.security; + +import java.security.Key; +import java.security.interfaces.DSAParams; +import java.util.HashMap; +import java.util.Map; + +import org.opensaml.xml.security.credential.Credential; +import org.opensaml.xml.security.keyinfo.KeyInfoCredentialResolver; +import org.opensaml.xml.security.keyinfo.NamedKeyInfoGeneratorManager; +import org.opensaml.xml.util.DatatypeHelper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Basic in-memory implementation of {@link SecurityConfiguration}. + */ +public class BasicSecurityConfiguration implements SecurityConfiguration { + + /** The name of the KeyInfoCredentialResolver default config. */ + public static final String KEYINFO_RESOLVER_DEFAULT_CONFIG = "_KEYINFO_RESOLVER_DEFAULT_"; + + /** Class logger. */ + private final Logger log = LoggerFactory.getLogger(BasicSecurityConfiguration.class); + + /** JCA algorithm to signature URI mappings. */ + private Map signatureAlgorithms; + + /** Signature canonicalization algorithm URI. */ + private String signatureCanonicalization; + + /** Signature Reference digest method algorithm URI. */ + private String signatureReferenceDigestMethod; + + /** Signature HMAC output length. */ + private Integer signatureHMACOutputLength; + + /** JCA algorithm to data encryption URI mappings. */ + private Map dataEncryptionAlgorithms; + + /** JCA algorithm to key transport encryption URI mappings. */ + private Map keyTransportEncryptionAlgorithms; + + /** Encryption algorithm URI for auto-generated data encryption keys. */ + private String autoGenEncryptionURI; + + /** Manager for named KeyInfoGenerator instances. */ + private NamedKeyInfoGeneratorManager keyInfoGeneratorManager; + + /** Set of named KeyInfoCredentialResolvers. */ + private Map keyInfoCredentialResolvers; + + /** Default DSA key family parameters. */ + private Map dsaParams; + + /** Constructor. */ + public BasicSecurityConfiguration() { + signatureAlgorithms = new HashMap(); + dataEncryptionAlgorithms = new HashMap(); + keyTransportEncryptionAlgorithms = new HashMap(); + keyInfoCredentialResolvers = new HashMap(); + dsaParams = new HashMap(); + } + + // Signature-related config + + /** {@inheritDoc} */ + public String getSignatureAlgorithmURI(String jcaAlgorithmName) { + return signatureAlgorithms.get(jcaAlgorithmName); + } + + /** {@inheritDoc} */ + public String getSignatureAlgorithmURI(Credential credential) { + Key key = SecurityHelper.extractSigningKey(credential); + if (key == null) { + log.debug("Could not extract signing key from credential, unable to map to algorithm URI"); + return null; + } else if (key.getAlgorithm() == null) { + log.debug("Signing key algorithm value was not available, unable to map to algorithm URI"); + return null; + } + return getSignatureAlgorithmURI(key.getAlgorithm()); + } + + /** + * Register a mapping from the specified JCA algorithm name to a signature algorithm URI. + * + * @param jcaAlgorithmName the JCA algorithm name to register + * @param algorithmURI the algorithm URI to register + */ + public void registerSignatureAlgorithmURI(String jcaAlgorithmName, String algorithmURI) { + signatureAlgorithms.put(jcaAlgorithmName, algorithmURI); + } + + /** + * Deregister a mapping for the specified JCA algorithm name. + * + * @param jcaAlgorithmName the JCA algorithm name to deregister + */ + public void deregisterSignatureAlgorithmURI(String jcaAlgorithmName) { + signatureAlgorithms.remove(jcaAlgorithmName); + } + + /** {@inheritDoc} */ + public String getSignatureCanonicalizationAlgorithm() { + return signatureCanonicalization; + } + + /** + * Set a canonicalization algorithm URI suitable for use as a Signature CanonicalizationMethod value. + * + * @param algorithmURI a canonicalization algorithm URI + */ + public void setSignatureCanonicalizationAlgorithm(String algorithmURI) { + signatureCanonicalization = algorithmURI; + } + + /** {@inheritDoc} */ + public String getSignatureReferenceDigestMethod() { + return signatureReferenceDigestMethod; + } + + /** + * Set a digest method algorithm URI suitable for use as a Signature Reference DigestMethod value. + * + * @param algorithmURI a digest method algorithm URI + */ + public void setSignatureReferenceDigestMethod(String algorithmURI) { + signatureReferenceDigestMethod = algorithmURI; + } + + /** {@inheritDoc} */ + public Integer getSignatureHMACOutputLength() { + return signatureHMACOutputLength; + } + + /** + * Set the value to be used as the Signature SignatureMethod HMACOutputLength value, used + * only when signing with an HMAC algorithm. This value is optional when using HMAC. + * + * @param length the HMAC output length value to use when performing HMAC signing (may be null) + */ + public void setSignatureHMACOutputLength(Integer length) { + signatureHMACOutputLength = length; + } + + // Encryption-related config + + /** {@inheritDoc} */ + public String getDataEncryptionAlgorithmURI(String jcaAlgorithmName, Integer keyLength) { + DataEncryptionIndex index = new DataEncryptionIndex(jcaAlgorithmName, keyLength); + String algorithmURI = dataEncryptionAlgorithms.get(index); + if (algorithmURI != null) { + return algorithmURI; + } + if (keyLength != null) { + // Fall through to default, i.e. with no specific key length registered + log.debug("No data encryption algorithm mapping available for JCA name + key length, " + + "trying JCA name alone"); + index = new DataEncryptionIndex(jcaAlgorithmName, null); + return dataEncryptionAlgorithms.get(index); + } + return null; + } + + /** {@inheritDoc} */ + public String getDataEncryptionAlgorithmURI(Credential credential) { + Key key = SecurityHelper.extractEncryptionKey(credential); + if (key == null) { + log.debug("Could not extract data encryption key from credential, unable to map to algorithm URI"); + return null; + } else if (key.getAlgorithm() == null){ + log.debug("Data encryption key algorithm value was not available, unable to map to algorithm URI"); + return null; + } + Integer length = SecurityHelper.getKeyLength(key); + return getDataEncryptionAlgorithmURI(key.getAlgorithm(), length); + } + + /** + * Register a mapping from the specified JCA algorithm name to an encryption algorithm URI. + * + * @param jcaAlgorithmName the JCA algorithm name to register + * @param keyLength the key length to register (may be null) + * @param algorithmURI the algorithm URI to register + */ + public void registerDataEncryptionAlgorithmURI(String jcaAlgorithmName, Integer keyLength, String algorithmURI) { + DataEncryptionIndex index = new DataEncryptionIndex(jcaAlgorithmName, keyLength); + dataEncryptionAlgorithms.put(index, algorithmURI); + } + + /** + * Deregister a mapping for the specified JCA algorithm name. + * + * @param jcaAlgorithmName the JCA algorithm name to deregister + * @param keyLength the key length to deregister (may be null) + */ + public void deregisterDataEncryptionAlgorithmURI(String jcaAlgorithmName, Integer keyLength) { + DataEncryptionIndex index = new DataEncryptionIndex(jcaAlgorithmName, keyLength); + dataEncryptionAlgorithms.remove(index); + } + + /** {@inheritDoc} */ + public String getKeyTransportEncryptionAlgorithmURI(String jcaAlgorithmName, Integer keyLength, + String wrappedKeyAlgorithm) { + + KeyTransportEncryptionIndex index = + new KeyTransportEncryptionIndex(jcaAlgorithmName, keyLength, wrappedKeyAlgorithm); + String algorithmURI = keyTransportEncryptionAlgorithms.get(index); + if (algorithmURI != null) { + return algorithmURI; + } + + if (wrappedKeyAlgorithm != null) { + // Fall through to case of no specific wrapped key algorithm registered + log.debug("No data encryption algorithm mapping available for JCA name + key length + wrapped algorithm, " + + "trying JCA name + key length"); + index = new KeyTransportEncryptionIndex(jcaAlgorithmName, keyLength, null); + algorithmURI = keyTransportEncryptionAlgorithms.get(index); + if (algorithmURI != null) { + return algorithmURI; + } + } + if (keyLength != null) { + // Fall through to case of no specific key length registered + log.debug("No data encryption algorithm mapping available for JCA name + key length + wrapped algorithm, " + + "trying JCA name + wrapped algorithm"); + index = new KeyTransportEncryptionIndex(jcaAlgorithmName, null, wrappedKeyAlgorithm); + algorithmURI = keyTransportEncryptionAlgorithms.get(index); + if (algorithmURI != null) { + return algorithmURI; + } + } + // Fall through to case of no specific key length or wrapped key algorithm registered + log.debug("No data encryption algorithm mapping available for JCA name + key length + wrapped algorithm, " + + "trying JCA name alone"); + index = new KeyTransportEncryptionIndex(jcaAlgorithmName, null, null); + return keyTransportEncryptionAlgorithms.get(index); + } + + /** {@inheritDoc} */ + public String getKeyTransportEncryptionAlgorithmURI(Credential credential, String wrappedKeyAlgorithm) { + Key key = SecurityHelper.extractEncryptionKey(credential); + if (key == null) { + log.debug("Could not extract key transport encryption key from credential, unable to map to algorithm URI"); + return null; + } else if (key.getAlgorithm() == null){ + log.debug("Key transport encryption key algorithm value was not available, unable to map to algorithm URI"); + return null; + } + Integer length = SecurityHelper.getKeyLength(key); + return getKeyTransportEncryptionAlgorithmURI(key.getAlgorithm(), length, wrappedKeyAlgorithm); + } + + /** + * Register a mapping from the specified JCA algorithm name to an encryption algorithm URI. + * + * @param jcaAlgorithmName the JCA algorithm name to register + * @param keyLength the key length to register (may be null) + * @param wrappedKeyAlgorithm the JCA algorithm name of the key to be encrypted (may be null) + * @param algorithmURI the algorithm URI to register + */ + public void registerKeyTransportEncryptionAlgorithmURI(String jcaAlgorithmName, Integer keyLength, + String wrappedKeyAlgorithm, String algorithmURI) { + + KeyTransportEncryptionIndex index = + new KeyTransportEncryptionIndex(jcaAlgorithmName, keyLength, wrappedKeyAlgorithm); + keyTransportEncryptionAlgorithms.put(index, algorithmURI); + } + + /** + * Deregister a mapping for the specified JCA algorithm name. + * + * @param jcaAlgorithmName the JCA algorithm name to deregister + * @param keyLength the key length to deregister (may be null) + * @param wrappedKeyAlgorithm the JCA algorithm name of the key to be encrypted (may be null) + */ + public void deregisterKeyTransportEncryptionAlgorithmURI(String jcaAlgorithmName, Integer keyLength, + String wrappedKeyAlgorithm) { + + KeyTransportEncryptionIndex index = + new KeyTransportEncryptionIndex(jcaAlgorithmName, keyLength, wrappedKeyAlgorithm); + keyTransportEncryptionAlgorithms.remove(index); + + } + + /** {@inheritDoc} */ + public String getAutoGeneratedDataEncryptionKeyAlgorithmURI() { + return autoGenEncryptionURI; + } + + /** + * Set the encryption algorithm URI to be used when auto-generating random data encryption keys. + * + * @param algorithmURI the encryption algorithm URI to use + */ + public void setAutoGeneratedDataEncryptionKeyAlgorithmURI(String algorithmURI) { + autoGenEncryptionURI = algorithmURI; + } + + + // KeyInfo-related config + + /** {@inheritDoc} */ + public NamedKeyInfoGeneratorManager getKeyInfoGeneratorManager() { + return keyInfoGeneratorManager; + } + /** + * Set the manager for named KeyInfoGenerator instances. + * + * @param keyInfoManager the KeyInfoGenerator manager to use + */ + public void setKeyInfoGeneratorManager(NamedKeyInfoGeneratorManager keyInfoManager) { + keyInfoGeneratorManager = keyInfoManager; + } + + /** {@inheritDoc} */ + public KeyInfoCredentialResolver getDefaultKeyInfoCredentialResolver() { + return keyInfoCredentialResolvers.get(KEYINFO_RESOLVER_DEFAULT_CONFIG); + } + + /** + * Set the default KeyInfoCredentialResolver config. + * + * @param resolver the default KeyInfoCredentialResolver + */ + public void setDefaultKeyInfoCredentialResolver(KeyInfoCredentialResolver resolver) { + keyInfoCredentialResolvers.put(KEYINFO_RESOLVER_DEFAULT_CONFIG, resolver); + } + + /** {@inheritDoc} */ + public KeyInfoCredentialResolver getKeyInfoCredentialResolver(String name) { + return keyInfoCredentialResolvers.get(name); + } + + /** + * Register a named KeyInfoCredentialResolver configuration. + * + * @param name the name of the configuration + * @param resolver the KeyInfoCredentialResolver to register + */ + public void registerKeyInfoCredentialResolver(String name, KeyInfoCredentialResolver resolver) { + keyInfoCredentialResolvers.put(name, resolver); + } + + /** + * Deregister a named KeyInfoCredentialResolver configuration. + * + * @param name the name of the configuration + */ + public void deregisterKeyInfoCredentialResolver(String name) { + keyInfoCredentialResolvers.remove(name); + } + + // Miscellaneous config + + /** {@inheritDoc} */ + public DSAParams getDSAParams(int keyLength) { + return dsaParams.get(keyLength); + } + + /** + * Set a DSA parameters instance which defines the default DSA key information to be used + * within a DSA "key family". + * + * @param keyLength the key length of the DSA parameters + * @param params the default DSA parameters instance + */ + public void setDSAParams(int keyLength, DSAParams params) { + dsaParams.put(keyLength, params); + } + + + /** + * Class used as an index to the data encryption algorithm URI map. + */ + protected class DataEncryptionIndex { + + /** The JCA key algorithm name. */ + private String keyAlgorithm; + + /** The key length. Optional, may be null. */ + private Integer keyLength; + + /** + * Constructor. + * + * @param jcaAlgorithmName the JCA algorithm name + * @param length the key length (optional, may be null) + */ + protected DataEncryptionIndex(String jcaAlgorithmName, Integer length) { + if (DatatypeHelper.isEmpty(jcaAlgorithmName)) { + throw new IllegalArgumentException("JCA Algorithm name may not be null or empty"); + } + keyAlgorithm = DatatypeHelper.safeTrimOrNullString(jcaAlgorithmName); + keyLength = length; + } + + /** {@inheritDoc} */ + public boolean equals(Object obj) { + if(obj == this){ + return true; + } + + if (! (obj instanceof DataEncryptionIndex)) { + return false; + } + DataEncryptionIndex other = (DataEncryptionIndex) obj; + + if (! this.keyAlgorithm.equals(other.keyAlgorithm)) { + return false; + } + if (this.keyLength == null) { + return other.keyLength == null; + } else { + return this.keyLength.equals(other.keyLength); + } + + } + + /** {@inheritDoc} */ + public int hashCode() { + int result = 17; + result = 37*result + keyAlgorithm.hashCode(); + if (keyLength != null) { + result = 37*result + keyLength.hashCode(); + } + return result; + } + + /** {@inheritDoc} */ + public String toString() { + return String.format("[%s,%s]", keyAlgorithm, keyLength); + } + + } + + /** + * Class used as an index to the key transport encryption algorithm URI map. + */ + protected class KeyTransportEncryptionIndex { + + /** The JCA key algorithm name. */ + private String keyAlgorithm; + + /** The key length. Optional, may be null. */ + private Integer keyLength; + + /** The JCA key algorithm name of the key to be encrypted. */ + private String wrappedAlgorithm; + + /** + * Constructor. + * + * @param jcaAlgorithmName the JCA algorithm name + * @param length the key length (optional, may be null) + * @param wrappedKeyAlgorithm the JCA algorithm name of the key to be encrypted (optional, may be null) + */ + protected KeyTransportEncryptionIndex(String jcaAlgorithmName, Integer length, String wrappedKeyAlgorithm) { + if (DatatypeHelper.isEmpty(jcaAlgorithmName)) { + throw new IllegalArgumentException("JCA Algorithm name may not be null or empty"); + } + keyAlgorithm = DatatypeHelper.safeTrimOrNullString(jcaAlgorithmName); + keyLength = length; + wrappedAlgorithm = DatatypeHelper.safeTrimOrNullString(wrappedKeyAlgorithm); + } + + /** {@inheritDoc} */ + public boolean equals(Object obj) { + if(obj == this){ + return true; + } + + if (! (obj instanceof KeyTransportEncryptionIndex)) { + return false; + } + KeyTransportEncryptionIndex other = (KeyTransportEncryptionIndex) obj; + + if (! this.keyAlgorithm.equals(other.keyAlgorithm)) { + return false; + } + if (this.keyLength == null) { + if (other.keyLength != null) { + return false; + } + } else { + if (! this.keyLength.equals(other.keyLength)) { + return false; + } + } + if (this.wrappedAlgorithm == null) { + return other.wrappedAlgorithm == null; + } else { + return this.wrappedAlgorithm.equals(other.wrappedAlgorithm); + } + } + + /** {@inheritDoc} */ + public int hashCode() { + int result = 17; + result = 37*result + keyAlgorithm.hashCode(); + if (keyLength != null) { + result = 37*result + keyLength.hashCode(); + } + if (wrappedAlgorithm != null) { + result = 37*result + wrappedAlgorithm.hashCode(); + } + return result; + } + + /** {@inheritDoc} */ + public String toString() { + return String.format("[%s,%s,%s]", keyAlgorithm, keyLength, wrappedAlgorithm); + } + + } +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/security/Criteria.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/security/Criteria.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/security/Criteria.java 17 Aug 2012 15:17:19 -0000 1.1 @@ -0,0 +1,25 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.security; + +/** + * A generic marker interface for representing criteria used in resolution or evaluation operations. + */ +public interface Criteria { + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/security/CriteriaFilteringIterable.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/security/CriteriaFilteringIterable.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/security/CriteriaFilteringIterable.java 17 Aug 2012 15:17:19 -0000 1.1 @@ -0,0 +1,69 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.security; + +import java.util.Iterator; +import java.util.Set; + +/** + * An implementation of {@link Iterable} which wraps another underlying Iterable in order to support + * production of instances of {@link CriteriaFilteringIterator} based on the underlying Iterable's Iterator. + * + * For iterator behavior and meaning and use of the parameters, see {@link CriteriaFilteringIterator}. + * + * @param the type of candidate elements being evaluated + */ +public class CriteriaFilteringIterable implements Iterable { + + /** The candidates to evaluate. */ + private Iterable candidates; + + /** The set of criteria against which to evaluate the candidates. */ + private Set> criteriaSet; + + /** Flag indicating whether the candidate must satisfy all the criteria in the set, or just one. */ + private boolean meetAll; + + /** Flag indicating how candidates which can not be evaluated by a criteria are to be handled. */ + private boolean unevaledSatisfies; + + /** + * Constructor. + * + * @param candidatesIterable the candidates to evaluate + * @param criteria the set of criteria against which to evaluate the candidates + * @param meetAllCriteria whether a candidate must meet all criteria, or just one + * @param unevaluableSatisfies whether a can-not-evaluate result of a particular criteria's evaluation + * is treated as the candidate having satisfied or not satisfied the criteria, for purposes + * of determinig whether to return the element + */ + public CriteriaFilteringIterable(Iterable candidatesIterable, Set> criteria, + boolean meetAllCriteria, boolean unevaluableSatisfies) { + + candidates = candidatesIterable; + criteriaSet = criteria; + meetAll = meetAllCriteria; + unevaledSatisfies = unevaluableSatisfies; + } + + /** {@inheritDoc} */ + public Iterator iterator() { + return new CriteriaFilteringIterator(candidates.iterator(), criteriaSet, meetAll, unevaledSatisfies); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/security/CriteriaFilteringIterator.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/security/CriteriaFilteringIterator.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/security/CriteriaFilteringIterator.java 17 Aug 2012 15:17:19 -0000 1.1 @@ -0,0 +1,174 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.security; + +import java.util.Iterator; +import java.util.NoSuchElementException; +import java.util.Set; + +/** + *

This implementation of {@link Iterator} wraps another Iterator of a particular type, containing candidates + * which are to be evaluated against a given set of {@link EvaluableCriteria}. When the iterator is traversed, + * criteria evaluation is performed on each candidate element of the underlying wrapped iterator + * via {@link EvaluableCriteria#evaluate(Object)}. Only those elements which satisfy the criteria indicated by + * the criteria set are returned by the Iterator, as follows.

+ * + *

If the parameter meetAllCriteria is true, then all criteria in the criteria + * set must be satisfied in order for the element to be returned. This in essence connects the criteria of the criteria + * set with a logical AND. If false, then if an element satisfies any of the criteria of the + * criteria set, it will be returned. This in essence connects the members of the criteria set with a logical + * OR.

+ * + *

If the parameter unevaluableSatisfies is true, then if a criteria's evaluation + * of the candidate via {@link EvaluableCriteria#evaluate(Object)} indicates that it is unable to evaluate + * the candidate, the criteria will be considered satisfied as far as the determination of whether to return + * the candidate. If false, then the criteria will be considered unsatisfied for purposes + * of this determination.

+ * + *

Care should be exercised in combining these two parameter values to achieve the desired result.

+ * + * @param the type of candidate elements being evaluated + */ +public class CriteriaFilteringIterator implements Iterator { + + /** The candidates to evaluate. */ + private Iterator candidateIter; + + /** The set of criteria against which to evaluate the candidates. */ + private Set> criteriaSet; + + /** Flag indicating whether the candidate must satisfy all the criteria in the set, or just one. */ + private boolean meetAll; + + /** Flag indicating how candidates which can not be evaluated by a criteria are to be handled. */ + private boolean unevaledSatisfies; + + /** The current candidate which will be returned by the next call to next(). */ + private T current; + + /** + * Constructor. + * + * @param candidatesIterator the candidates to evaluate + * @param criteria the set of criteria against which to evaluate the candidates + * @param meetAllCriteria whether a candidate must meet all criteria, or just one + * @param unevaluableSatisfies whether a can-not-evaluate result of a particular criteria's evaluation + * is treated as the candidate having satisfied or not satisfied the criteria, for purposes + * of determinig whether to return the element + */ + public CriteriaFilteringIterator(Iterator candidatesIterator, + Set> criteria, boolean meetAllCriteria, boolean unevaluableSatisfies) { + + candidateIter = candidatesIterator; + criteriaSet = criteria; + meetAll = meetAllCriteria; + unevaledSatisfies = unevaluableSatisfies; + + current = null; + } + + /** {@inheritDoc} */ + public boolean hasNext() { + if (current != null) { + return true; + } + current = getNextMatch(); + if (current != null) { + return true; + } + return false; + } + + /** {@inheritDoc} */ + public T next() { + T temp; + if (current != null) { + temp = current; + current = null; + return temp; + } + temp = getNextMatch(); + if (temp != null) { + return temp; + } else { + throw new NoSuchElementException("No more elements are available"); + } + } + + /** {@inheritDoc} */ + public void remove() { + throw new UnsupportedOperationException("Remove operation is not supported by this iterator"); + } + + /** + * Get the next matching candidate. + * + * @return the next matching candidate + */ + private T getNextMatch() { + while (candidateIter.hasNext()) { + T candidate = candidateIter.next(); + if (match(candidate)) { + return candidate; + } + } + return null; + } + + /** + * Evaluate the candidate against all the criteria. + * + * @param candidate the candidate to evaluate + * @return true if the candidate satisfies the set of criteria, false otherwise + */ + private boolean match(T candidate) { + boolean sawOneSatisfied = false; + + // Edge case of empty criteria, should match everything + if (criteriaSet.isEmpty()) { + return true; + } + + for (EvaluableCriteria criteria : criteriaSet) { + Boolean result = criteria.evaluate(candidate); + if (result == Boolean.FALSE) { + if (meetAll) { + return false; + } + } else if (result == Boolean.TRUE) { + if (!meetAll) { + return true; + } + sawOneSatisfied = true; + } else { + // Was null, criteria said could not evaluate + if (meetAll && !unevaledSatisfies) { + return false; + } else if (!meetAll && unevaledSatisfies) { + return true; + } + if (unevaledSatisfies) { + sawOneSatisfied = true; + } + } + } + return sawOneSatisfied; + } + +} + \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/security/CriteriaSet.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/security/CriteriaSet.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/security/CriteriaSet.java 17 Aug 2012 15:17:19 -0000 1.1 @@ -0,0 +1,46 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.security; + +import org.opensaml.xml.util.ClassIndexedSet; + +/** + * This class holds instances of {@link Criteria} which are used + * in resolution or evaluation operations. + */ +public class CriteriaSet extends ClassIndexedSet { + + /** + * Constructor. + * + */ + public CriteriaSet() { + super(); + } + + /** + * A convenience constructor for constructing and adding a single criteria. + * + * @param criteria a single criteria + */ + public CriteriaSet(Criteria criteria) { + super(); + add(criteria); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/security/DefaultSecurityConfigurationBootstrap.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/security/DefaultSecurityConfigurationBootstrap.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/security/DefaultSecurityConfigurationBootstrap.java 17 Aug 2012 15:17:19 -0000 1.1 @@ -0,0 +1,161 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.security; + +import java.util.ArrayList; + +import org.opensaml.xml.encryption.EncryptionConstants; +import org.opensaml.xml.security.credential.BasicKeyInfoGeneratorFactory; +import org.opensaml.xml.security.keyinfo.BasicProviderKeyInfoCredentialResolver; +import org.opensaml.xml.security.keyinfo.KeyInfoCredentialResolver; +import org.opensaml.xml.security.keyinfo.KeyInfoGeneratorManager; +import org.opensaml.xml.security.keyinfo.KeyInfoProvider; +import org.opensaml.xml.security.keyinfo.NamedKeyInfoGeneratorManager; +import org.opensaml.xml.security.keyinfo.provider.DSAKeyValueProvider; +import org.opensaml.xml.security.keyinfo.provider.RSAKeyValueProvider; +import org.opensaml.xml.security.keyinfo.provider.InlineX509DataProvider; +import org.opensaml.xml.security.x509.X509KeyInfoGeneratorFactory; +import org.opensaml.xml.signature.SignatureConstants; + +/** + * A utility class which programatically builds an instance of {@link BasicSecurityConfiguration} + * which has reasonable default values for the various configuration parameters. + */ +public class DefaultSecurityConfigurationBootstrap { + + /** Constructor. */ + protected DefaultSecurityConfigurationBootstrap() {} + + /** + * Build and return a default configuration. + * + * @return a new basic security configuration with reasonable default values + */ + public static BasicSecurityConfiguration buildDefaultConfig() { + BasicSecurityConfiguration config = new BasicSecurityConfiguration(); + + populateSignatureParams(config); + populateEncryptionParams(config); + populateKeyInfoCredentialResolverParams(config); + populateKeyInfoGeneratorManager(config); + populateKeyParams(config); + + return config; + } + + /** + * Populate signature-related parameters. + * + * @param config the security configuration to populate + */ + protected static void populateSignatureParams(BasicSecurityConfiguration config) { + // Asymmetric key algorithms + config.registerSignatureAlgorithmURI("RSA", SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA1); + config.registerSignatureAlgorithmURI("DSA", SignatureConstants.ALGO_ID_SIGNATURE_DSA); + config.registerSignatureAlgorithmURI("ECDSA", SignatureConstants.ALGO_ID_SIGNATURE_ECDSA_SHA1); + + // HMAC algorithms + config.registerSignatureAlgorithmURI("AES", SignatureConstants.ALGO_ID_MAC_HMAC_SHA1); + config.registerSignatureAlgorithmURI("DESede", SignatureConstants.ALGO_ID_MAC_HMAC_SHA1); + + // Other signature-related params + config.setSignatureCanonicalizationAlgorithm(SignatureConstants.ALGO_ID_C14N_EXCL_OMIT_COMMENTS); + config.setSignatureHMACOutputLength(null); + config.setSignatureReferenceDigestMethod(SignatureConstants.ALGO_ID_DIGEST_SHA1); + } + + /** + * Populate encryption-related parameters. + * + * @param config the security configuration to populate + */ + protected static void populateEncryptionParams(BasicSecurityConfiguration config) { + // Data encryption URI's + config.registerDataEncryptionAlgorithmURI("AES", 128, EncryptionConstants.ALGO_ID_BLOCKCIPHER_AES128); + config.registerDataEncryptionAlgorithmURI("AES", 192, EncryptionConstants.ALGO_ID_BLOCKCIPHER_AES192); + config.registerDataEncryptionAlgorithmURI("AES", 256, EncryptionConstants.ALGO_ID_BLOCKCIPHER_AES256); + config.registerDataEncryptionAlgorithmURI("DESede", 168, EncryptionConstants.ALGO_ID_BLOCKCIPHER_TRIPLEDES); + config.registerDataEncryptionAlgorithmURI("DESede", 192, EncryptionConstants.ALGO_ID_BLOCKCIPHER_TRIPLEDES); + + // Key encryption URI's + + // Asymmetric key transport algorithms + config.registerKeyTransportEncryptionAlgorithmURI("RSA", null, "AES", EncryptionConstants.ALGO_ID_KEYTRANSPORT_RSAOAEP); + config.registerKeyTransportEncryptionAlgorithmURI("RSA", null, "DESede", EncryptionConstants.ALGO_ID_KEYTRANSPORT_RSAOAEP); + + // Symmetric key wrap algorithms + config.registerKeyTransportEncryptionAlgorithmURI("AES", 128, null, EncryptionConstants.ALGO_ID_KEYWRAP_AES128); + config.registerKeyTransportEncryptionAlgorithmURI("AES", 192, null, EncryptionConstants.ALGO_ID_KEYWRAP_AES192); + config.registerKeyTransportEncryptionAlgorithmURI("AES", 256, null, EncryptionConstants.ALGO_ID_KEYWRAP_AES256); + config.registerKeyTransportEncryptionAlgorithmURI("DESede", 168, null, EncryptionConstants.ALGO_ID_KEYWRAP_TRIPLEDES); + config.registerKeyTransportEncryptionAlgorithmURI("DESede", 192, null, EncryptionConstants.ALGO_ID_KEYWRAP_TRIPLEDES); + + // Other encryption-related params + config.setAutoGeneratedDataEncryptionKeyAlgorithmURI(EncryptionConstants.ALGO_ID_BLOCKCIPHER_AES128); + } + + /** + * Populate KeyInfoCredentialResolver-related parameters. + * + * @param config the security configuration to populate + */ + protected static void populateKeyInfoCredentialResolverParams(BasicSecurityConfiguration config) { + // Basic resolver for inline info + ArrayList providers = new ArrayList(); + providers.add( new RSAKeyValueProvider() ); + providers.add( new DSAKeyValueProvider() ); + providers.add( new InlineX509DataProvider() ); + + KeyInfoCredentialResolver resolver = new BasicProviderKeyInfoCredentialResolver(providers); + config.setDefaultKeyInfoCredentialResolver(resolver); + } + + /** + * Populate KeyInfoGeneratorManager-related parameters. + * + * @param config the security configuration to populate + */ + protected static void populateKeyInfoGeneratorManager(BasicSecurityConfiguration config) { + NamedKeyInfoGeneratorManager namedManager = new NamedKeyInfoGeneratorManager(); + config.setKeyInfoGeneratorManager(namedManager); + + namedManager.setUseDefaultManager(true); + KeyInfoGeneratorManager defaultManager = namedManager.getDefaultManager(); + + // Generator for basic Credentials + BasicKeyInfoGeneratorFactory basicFactory = new BasicKeyInfoGeneratorFactory(); + basicFactory.setEmitPublicKeyValue(true); + + // Generator for X509Credentials + X509KeyInfoGeneratorFactory x509Factory = new X509KeyInfoGeneratorFactory(); + x509Factory.setEmitEntityCertificate(true); + + defaultManager.registerFactory(basicFactory); + defaultManager.registerFactory(x509Factory); + } + + /** + * Populate misc key-related parameters. + * + * @param config the security configuration to populate + */ + protected static void populateKeyParams(BasicSecurityConfiguration config) { + // Maybe populate some DSA parameters here, if there are commonly accepcted default values + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/security/EvaluableCriteria.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/security/EvaluableCriteria.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/security/EvaluableCriteria.java 17 Aug 2012 15:17:19 -0000 1.1 @@ -0,0 +1,42 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.security; + +/** + * Interface for criteria which are capable of evaluating a target of a particular type. + * + * @param the type of object which may be evaluated + */ +public interface EvaluableCriteria extends Criteria { + + /** + * Evaluate the target. + * + * The result of evaluation is one of the following values: + *
    + *
  • Boolean.TRUE if the target satisfies the criteria
  • + *
  • Boolean.FALSE if the target does not satisfy criteria
  • + *
  • null if the target can not be evaluated against the criteria
  • + *
+ * + * @param target the object to be evaluated + * @return the result of evaluation + */ + public Boolean evaluate(T target); + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/security/Resolver.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/security/Resolver.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/security/Resolver.java 17 Aug 2012 15:17:19 -0000 1.1 @@ -0,0 +1,53 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.security; + + +/** + * Generic interface for resolvers which process specified criteria and produce some implementation-specific + * result information. + * + * @param the type of objects produced by this resolver + * @param the type of criteria to process during resolution + */ +public interface Resolver { + + + /** + * Process the specified criteria and return the resulting instances the the product type + * which satisfy the criteria. + * + * @param criteria the criteria to evaluate or process + * @return instances which satisfy the criteria + * @throws SecurityException thrown if there is an error processing the specified criteria + */ + Iterable resolve(CriteriaType criteria) throws SecurityException; + + /** + * Process the specified criteria and return a single instance of the product type + * which satisfies the criteria. + * + * If multiple items satisfy the criteria, the choice of which single item to + * return is implementation-dependent. + * + * @param criteria the criteria to evaluate or process + * @return instances which satisfy the criteria + * @throws SecurityException thrown if there is an error processing the specified criteria + */ + ProductType resolveSingle(CriteriaType criteria) throws SecurityException; +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/security/SecurityConfiguration.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/security/SecurityConfiguration.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/security/SecurityConfiguration.java 17 Aug 2012 15:17:19 -0000 1.1 @@ -0,0 +1,159 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.security; + +import java.security.interfaces.DSAParams; + +import org.opensaml.xml.security.credential.Credential; +import org.opensaml.xml.security.keyinfo.KeyInfoCredentialResolver; +import org.opensaml.xml.security.keyinfo.NamedKeyInfoGeneratorManager; + +/** + * Interface for classes which store security-related configuration information, especially + * related to the requirements for XML Signature and XML Encryption. + */ +public interface SecurityConfiguration { + + /** + * Get the signature algorithm URI for the specified JCA key algorithm name. + * + * @param jcaAlgorithmName a JCA key algorithm name + * @return a signature algorithm URI mapping, or null if no mapping is available + */ + public String getSignatureAlgorithmURI(String jcaAlgorithmName); + + /** + * Get the signature algorithm URI for the signing key contained within the specified credential. + * + * @param credential a credential containing a signing key + * @return a signature algorithm URI mapping, or null if no mapping is available + */ + public String getSignatureAlgorithmURI(Credential credential); + + /** + * Get a digest method algorithm URI suitable for use as a Signature Reference DigestMethod value. + * + * @return a digest method algorithm URI + */ + public String getSignatureReferenceDigestMethod(); + + /** + * Get a canonicalization algorithm URI suitable for use as a Signature CanonicalizationMethod value. + * + * @return a canonicalization algorithm URI + */ + public String getSignatureCanonicalizationAlgorithm(); + + /** + * Get the value to be used as the Signature SignatureMethod HMACOutputLength value, used + * only when signing with an HMAC algorithm. This value is optional when using HMAC. + * + * @return the configured HMAC output length value + */ + public Integer getSignatureHMACOutputLength(); + + /** + * Get the encryption algorithm URI for the specified JCA key algorithm name and optional key + * length. + * + * Passing null as the key length will return the default algorithm URI for the specified + * JCA algorithm, if a default is configured. If no mapping for the specified key length is available, + * the default mapping will be returned. + * + * @param jcaAlgorithmName a JCA key algorithm name + * @param keyLength optional key length parameter + * @return an encryption algorithm URI, or null if no mapping is available + */ + public String getDataEncryptionAlgorithmURI(String jcaAlgorithmName, Integer keyLength); + + /** + * Get the encryption algorithm URI for the encryption key contained within the specified credential. + * + * @param credential a credential containing an encryption key + * @return an encryption algorithm URI mapping, or null if no mapping is available + */ + public String getDataEncryptionAlgorithmURI(Credential credential); + + /** + * Get the key transport encryption algorithm URI for the specified JCA key algorithm name, optional key + * length and optional JCA key algorithm name of the key to be encrypted. + * + * Note that typically the key length parameter is required for lookup of symmetric key wrap algorithm + * URI's, but is typically not required or relevant for asymmetric key transport algorithms. + * + * If a mapping is not available considering the optional key length and wrapped algorithm parameters as passed, + * a lookup will next be attempted by omiting the (non-null) wrapped key algorithm, and if that is unsuccessful, + * by then omitting the (non-null) key length parameter. If a mapping has still not been found, then a final + * lookup attempt will be made using the key encryption key's JCA algorithm name alone. + * + * @param jcaAlgorithmName a JCA key algorithm name for the key encryption key + * @param keyLength optional key length parameter + * @param wrappedKeyAlgorithm a JCA key algorithm name for the key to be encrypted + * @return an encryption algorithm URI, or null if no mapping is available + */ + public String getKeyTransportEncryptionAlgorithmURI(String jcaAlgorithmName, Integer keyLength, + String wrappedKeyAlgorithm); + + /** + * Get the key transport encryption algorithm URI for the encryption key contained within the specified credential. + * + * @param credential a credential containing an encryption key + * @param wrappedKeyAlgorithm the JCA key algorithm name of the key being encrypted + * @return an encryption algorithm URI mapping, or null if no mapping is available + */ + public String getKeyTransportEncryptionAlgorithmURI(Credential credential, String wrappedKeyAlgorithm); + + /** + * Get the encryption algorithm URI to be used when auto-generating random data encryption keys. + * + * @return an encryption algorithm URI, or null if no default is available + */ + public String getAutoGeneratedDataEncryptionKeyAlgorithmURI(); + + /** + * Get a DSA parameters instance which defines the default DSA key information to be used + * within a DSA "key family". + * + * @param keyLength length of the DSA key whose parameters are desired + * @return the default DSA parameters instance, or null if no default is available + */ + public DSAParams getDSAParams(int keyLength); + + /** + * Get the manager for named KeyInfoGenerator instances. + * + * @return the KeyInfoGenerator manager, or null if none is configured + */ + public NamedKeyInfoGeneratorManager getKeyInfoGeneratorManager(); + + /** + * Get the KeyInfoCredentialResolver associated with the named configuration. + * + * @param name the name of the resolver configuration to return + * @return a KeyInfoCredentialResolver instance + */ + public KeyInfoCredentialResolver getKeyInfoCredentialResolver(String name); + + /** + * Get the default KeyInfoCredentialResolver configuration. + * + * @return the default KeyInfoCredentialResolver + */ + public KeyInfoCredentialResolver getDefaultKeyInfoCredentialResolver(); + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/security/SecurityException.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/security/SecurityException.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/security/SecurityException.java 17 Aug 2012 15:17:19 -0000 1.1 @@ -0,0 +1,62 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.security; + +/** + * Base exception for security related errors. + */ +public class SecurityException extends Exception { + + /** Serial version UID. */ + private static final long serialVersionUID = 485895728446891757L; + + /** + * Constructor. + */ + public SecurityException() { + super(); + } + + /** + * Constructor. + * + * @param message exception message + */ + public SecurityException(String message) { + super(message); + } + + /** + * Constructor. + * + * @param wrappedException exception to be wrapped by this one + */ + public SecurityException(Exception wrappedException) { + super(wrappedException); + } + + /** + * Constructor. + * + * @param message exception message + * @param wrappedException exception to be wrapped by this one + */ + public SecurityException(String message, Exception wrappedException) { + super(message, wrappedException); + } +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/security/SecurityHelper.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/security/SecurityHelper.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/security/SecurityHelper.java 17 Aug 2012 15:17:18 -0000 1.1 @@ -0,0 +1,1092 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.security; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.IOException; +import java.math.BigInteger; +import java.security.GeneralSecurityException; +import java.security.Key; +import java.security.KeyException; +import java.security.KeyFactory; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.cert.CRLException; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; +import java.security.interfaces.DSAParams; +import java.security.interfaces.DSAPrivateKey; +import java.security.interfaces.DSAPublicKey; +import java.security.interfaces.ECPublicKey; +import java.security.interfaces.RSAPrivateCrtKey; +import java.security.interfaces.RSAPrivateKey; +import java.security.interfaces.RSAPublicKey; +import java.security.spec.DSAPublicKeySpec; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.KeySpec; +import java.security.spec.RSAPublicKeySpec; +import java.security.spec.X509EncodedKeySpec; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import javax.crypto.KeyGenerator; +import javax.crypto.SecretKey; + +import org.apache.commons.ssl.PKCS8Key; +import org.apache.xml.security.Init; +import org.apache.xml.security.algorithms.JCEMapper; +import org.opensaml.xml.Configuration; +import org.opensaml.xml.encryption.EncryptionParameters; +import org.opensaml.xml.encryption.KeyEncryptionParameters; +import org.opensaml.xml.security.credential.BasicCredential; +import org.opensaml.xml.security.credential.Credential; +import org.opensaml.xml.security.keyinfo.BasicProviderKeyInfoCredentialResolver; +import org.opensaml.xml.security.keyinfo.KeyInfoCredentialResolver; +import org.opensaml.xml.security.keyinfo.KeyInfoGenerator; +import org.opensaml.xml.security.keyinfo.KeyInfoGeneratorFactory; +import org.opensaml.xml.security.keyinfo.KeyInfoProvider; +import org.opensaml.xml.security.keyinfo.NamedKeyInfoGeneratorManager; +import org.opensaml.xml.security.keyinfo.provider.DSAKeyValueProvider; +import org.opensaml.xml.security.keyinfo.provider.InlineX509DataProvider; +import org.opensaml.xml.security.keyinfo.provider.RSAKeyValueProvider; +import org.opensaml.xml.security.x509.BasicX509Credential; +import org.opensaml.xml.signature.KeyInfo; +import org.opensaml.xml.signature.Signature; +import org.opensaml.xml.signature.SignatureConstants; +import org.opensaml.xml.util.Base64; +import org.opensaml.xml.util.DatatypeHelper; +import org.opensaml.xml.util.LazySet; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Helper methods for security-related requirements. + */ +public final class SecurityHelper { + + /** Additional algorithm URI's which imply RSA keys. */ + private static Set rsaAlgorithmURIs; + + /** Additional algorithm URI's which imply DSA keys. */ + private static Set dsaAlgorithmURIs; + + /** Additional algorithm URI's which imply ECDSA keys. */ + private static Set ecdsaAlgorithmURIs; + + /** Constructor. */ + private SecurityHelper() { + } + + /** + * Get the Java security JCA/JCE algorithm identifier associated with an algorithm URI. + * + * @param algorithmURI the algorithm URI to evaluate + * @return the Java algorithm identifier, or null if the mapping is unavailable or indeterminable from the URI + */ + public static String getAlgorithmIDFromURI(String algorithmURI) { + return DatatypeHelper.safeTrimOrNullString(JCEMapper.translateURItoJCEID(algorithmURI)); + } + + /** + * Check whether the signature method algorithm URI indicates HMAC. + * + * @param signatureAlgorithm the signature method algorithm URI + * @return true if URI indicates HMAC, false otherwise + */ + public static boolean isHMAC(String signatureAlgorithm) { + String algoClass = DatatypeHelper.safeTrimOrNullString(JCEMapper.getAlgorithmClassFromURI(signatureAlgorithm)); + return ApacheXMLSecurityConstants.ALGO_CLASS_MAC.equals(algoClass); + } + + /** + * Get the Java security JCA/JCE key algorithm specifier associated with an algorithm URI. + * + * @param algorithmURI the algorithm URI to evaluate + * @return the Java key algorithm specifier, or null if the mapping is unavailable or indeterminable from the URI + */ + public static String getKeyAlgorithmFromURI(String algorithmURI) { + // The default Apache config file currently only includes the key algorithm for + // the block ciphers and key wrap URI's. Note: could use a custom config file which contains others. + String apacheValue = DatatypeHelper.safeTrimOrNullString(JCEMapper.getJCEKeyAlgorithmFromURI(algorithmURI)); + if (apacheValue != null) { + return apacheValue; + } + + // HMAC uses any symmetric key, so there is no implied specific key algorithm + if (isHMAC(algorithmURI)) { + return null; + } + + // As a last ditch fallback, check some known common and supported ones. + if (rsaAlgorithmURIs.contains(algorithmURI)) { + return "RSA"; + } + if (dsaAlgorithmURIs.contains(algorithmURI)) { + return "DSA"; + } + if (ecdsaAlgorithmURIs.contains(algorithmURI)) { + return "ECDSA"; + } + + return null; + } + + /** + * Get the length of the key indicated by the algorithm URI, if applicable and available. + * + * @param algorithmURI the algorithm URI to evaluate + * @return the length of the key indicated by the algorithm URI, or null if the length is either unavailable or + * indeterminable from the URI + */ + public static Integer getKeyLengthFromURI(String algorithmURI) { + Logger log = getLogger(); + String algoClass = DatatypeHelper.safeTrimOrNullString(JCEMapper.getAlgorithmClassFromURI(algorithmURI)); + + if (ApacheXMLSecurityConstants.ALGO_CLASS_BLOCK_ENCRYPTION.equals(algoClass) + || ApacheXMLSecurityConstants.ALGO_CLASS_SYMMETRIC_KEY_WRAP.equals(algoClass)) { + + try { + int keyLength = JCEMapper.getKeyLengthFromURI(algorithmURI); + return new Integer(keyLength); + } catch (NumberFormatException e) { + log.warn("XML Security config contained invalid key length value for algorithm URI: " + algorithmURI); + } + } + + log.info("Mapping from algorithm URI {} to key length not available", algorithmURI); + return null; + } + + /** + * Generates a random Java JCE symmetric Key object from the specified XML Encryption algorithm URI. + * + * @param algoURI The XML Encryption algorithm URI + * @return a randomly-generated symmetric Key + * @throws NoSuchAlgorithmException thrown if the specified algorithm is invalid + * @throws KeyException thrown if the length of the key to generate could not be determined + */ + public static SecretKey generateSymmetricKey(String algoURI) throws NoSuchAlgorithmException, KeyException { + Logger log = getLogger(); + String jceAlgorithmName = getKeyAlgorithmFromURI(algoURI); + if (DatatypeHelper.isEmpty(jceAlgorithmName)) { + log.error("Mapping from algorithm URI '" + algoURI + + "' to key algorithm not available, key generation failed"); + throw new NoSuchAlgorithmException("Algorithm URI'" + algoURI + "' is invalid for key generation"); + } + Integer keyLength = getKeyLengthFromURI(algoURI); + if (keyLength == null) { + log.error("Key length could not be determined from algorithm URI, can't generate key"); + throw new KeyException("Key length not determinable from algorithm URI, could not generate new key"); + } + KeyGenerator keyGenerator = KeyGenerator.getInstance(jceAlgorithmName); + keyGenerator.init(keyLength); + return keyGenerator.generateKey(); + } + + /** + * Extract the encryption key from the credential. + * + * @param credential the credential containing the encryption key + * @return the encryption key (either a public key or a secret (symmetric) key + */ + public static Key extractEncryptionKey(Credential credential) { + if (credential == null) { + return null; + } + if (credential.getPublicKey() != null) { + return credential.getPublicKey(); + } else { + return credential.getSecretKey(); + } + } + + /** + * Extract the decryption key from the credential. + * + * @param credential the credential containing the decryption key + * @return the decryption key (either a private key or a secret (symmetric) key + */ + public static Key extractDecryptionKey(Credential credential) { + if (credential == null) { + return null; + } + if (credential.getPrivateKey() != null) { + return credential.getPrivateKey(); + } else { + return credential.getSecretKey(); + } + } + + /** + * Extract the signing key from the credential. + * + * @param credential the credential containing the signing key + * @return the signing key (either a private key or a secret (symmetric) key + */ + public static Key extractSigningKey(Credential credential) { + if (credential == null) { + return null; + } + if (credential.getPrivateKey() != null) { + return credential.getPrivateKey(); + } else { + return credential.getSecretKey(); + } + } + + /** + * Extract the verification key from the credential. + * + * @param credential the credential containing the verification key + * @return the verification key (either a public key or a secret (symmetric) key + */ + public static Key extractVerificationKey(Credential credential) { + if (credential == null) { + return null; + } + if (credential.getPublicKey() != null) { + return credential.getPublicKey(); + } else { + return credential.getSecretKey(); + } + } + + /** + * Get the key length in bits of the specified key. + * + * @param key the key to evaluate + * @return length of the key in bits, or null if the length can not be determined + */ + public static Integer getKeyLength(Key key) { + Logger log = getLogger(); + // TODO investigate techniques (and use cases) to determine length in other cases, + // e.g. RSA and DSA keys, and non-RAW format symmetric keys + if (key instanceof SecretKey && "RAW".equals(key.getFormat())) { + return key.getEncoded().length * 8; + } + log.debug("Unable to determine length in bits of specified Key instance"); + return null; + } + + /** + * Get a simple, minimal credential containing a secret (symmetric) key. + * + * @param secretKey the symmetric key to wrap + * @return a credential containing the secret key specified + */ + public static BasicCredential getSimpleCredential(SecretKey secretKey) { + if (secretKey == null) { + throw new IllegalArgumentException("A secret key is required"); + } + BasicCredential cred = new BasicCredential(); + cred.setSecretKey(secretKey); + return cred; + } + + /** + * Get a simple, minimal credential containing a public key, and optionally a private key. + * + * @param publicKey the public key to wrap + * @param privateKey the private key to wrap, which may be null + * @return a credential containing the key(s) specified + */ + public static BasicCredential getSimpleCredential(PublicKey publicKey, PrivateKey privateKey) { + if (publicKey == null) { + throw new IllegalArgumentException("A public key is required"); + } + BasicCredential cred = new BasicCredential(); + cred.setPublicKey(publicKey); + cred.setPrivateKey(privateKey); + return cred; + } + + /** + * Get a simple, minimal credential containing an end-entity X.509 certificate, and optionally a private key. + * + * @param cert the end-entity certificate to wrap + * @param privateKey the private key to wrap, which may be null + * @return a credential containing the certificate and key specified + */ + public static BasicX509Credential getSimpleCredential(X509Certificate cert, PrivateKey privateKey) { + if (cert == null) { + throw new IllegalArgumentException("A certificate is required"); + } + BasicX509Credential cred = new BasicX509Credential(); + cred.setEntityCertificate(cert); + cred.setPrivateKey(privateKey); + return cred; + } + + /** + * Decodes secret keys in DER and PEM format. + * + * This method is not yet implemented. + * + * @param key secret key + * @param password password if the key is encrypted or null if not + * + * @return the decoded key + * + * @throws KeyException thrown if the key can not be decoded + */ + public static SecretKey decodeSecretKey(byte[] key, char[] password) throws KeyException { + // TODO + throw new UnsupportedOperationException("This method is not yet supported"); + } + + /** + * Decodes RSA/DSA public keys in DER-encoded "SubjectPublicKeyInfo" format. + * + * @param key encoded key + * @param password password if the key is encrypted or null if not + * + * @return decoded key + * + * @throws KeyException thrown if the key can not be decoded + */ + public static PublicKey decodePublicKey(byte[] key, char[] password) throws KeyException { + X509EncodedKeySpec keySpec = new X509EncodedKeySpec(key); + try { + return buildKey(keySpec, "RSA"); + } + catch (KeyException ex) { + } + try { + return buildKey(keySpec, "DSA"); + } + catch (KeyException ex) { + } + try { + return buildKey(keySpec, "EC"); + } + catch (KeyException ex) { + } + throw new KeyException("Unsupported key type."); + } + + /** + * Derives the public key from either a DSA or RSA private key. + * + * @param key the private key to derive the public key from + * + * @return the derived public key + * + * @throws KeyException thrown if the given private key is not a DSA or RSA key or there is a problem generating the + * public key + */ + public static PublicKey derivePublicKey(PrivateKey key) throws KeyException { + KeyFactory factory; + if (key instanceof DSAPrivateKey) { + DSAPrivateKey dsaKey = (DSAPrivateKey) key; + DSAParams keyParams = dsaKey.getParams(); + BigInteger y = keyParams.getQ().modPow(dsaKey.getX(), keyParams.getP()); + DSAPublicKeySpec pubKeySpec = new DSAPublicKeySpec(y, keyParams.getP(), keyParams.getQ(), keyParams.getG()); + + try { + factory = KeyFactory.getInstance("DSA"); + return factory.generatePublic(pubKeySpec); + } catch (GeneralSecurityException e) { + throw new KeyException("Unable to derive public key from DSA private key", e); + } + } else if (key instanceof RSAPrivateCrtKey) { + RSAPrivateCrtKey rsaKey = (RSAPrivateCrtKey) key; + RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(rsaKey.getModulus(), rsaKey.getPublicExponent()); + + try { + factory = KeyFactory.getInstance("RSA"); + return factory.generatePublic(pubKeySpec); + } catch (GeneralSecurityException e) { + throw new KeyException("Unable to derive public key from RSA private key", e); + } + } else { + throw new KeyException("Private key was not a DSA or RSA key"); + } + } + + /** + * Decodes RSA/DSA private keys in DER, PEM, or PKCS#8 (encrypted or unencrypted) formats. + * + * @param key encoded key + * @param password decryption password or null if the key is not encrypted + * + * @return deocded private key + * + * @throws KeyException thrown if the key can not be decoded + */ + public static PrivateKey decodePrivateKey(File key, char[] password) throws KeyException { + if (!key.exists()) { + throw new KeyException("Key file " + key.getAbsolutePath() + " does not exist"); + } + + if (!key.canRead()) { + throw new KeyException("Key file " + key.getAbsolutePath() + " is not readable"); + } + + try { + return decodePrivateKey(DatatypeHelper.fileToByteArray(key), password); + } catch (IOException e) { + throw new KeyException("Error reading Key file " + key.getAbsolutePath(), e); + } + } + + /** + * Decodes RSA/DSA private keys in DER, PEM, or PKCS#8 (encrypted or unencrypted) formats. + * + * @param key encoded key + * @param password decryption password or null if the key is not encrypted + * + * @return deocded private key + * + * @throws KeyException thrown if the key can not be decoded + */ + public static PrivateKey decodePrivateKey(byte[] key, char[] password) throws KeyException { + try { + PKCS8Key deocodedKey = new PKCS8Key(key, password); + return deocodedKey.getPrivateKey(); + } catch (GeneralSecurityException e) { + throw new KeyException("Unable to decode private key", e); + } + } + + /** + * Build Java certificate from base64 encoding. + * + * @param base64Cert base64-encoded certificate + * @return a native Java X509 certificate + * @throws CertificateException thrown if there is an error constructing certificate + */ + public static java.security.cert.X509Certificate buildJavaX509Cert(String base64Cert) throws CertificateException { + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + ByteArrayInputStream input = new ByteArrayInputStream(Base64.decode(base64Cert)); + return (java.security.cert.X509Certificate) cf.generateCertificate(input); + } + + /** + * Build Java CRL from base64 encoding. + * + * @param base64CRL base64-encoded CRL + * @return a native Java X509 CRL + * @throws CertificateException thrown if there is an error constructing certificate + * @throws CRLException thrown if there is an error constructing CRL + */ + public static java.security.cert.X509CRL buildJavaX509CRL(String base64CRL) + throws CertificateException, CRLException { + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + ByteArrayInputStream input = new ByteArrayInputStream(Base64.decode(base64CRL)); + return (java.security.cert.X509CRL) cf.generateCRL(input); + } + + /** + * Build Java DSA public key from base64 encoding. + * + * @param base64EncodedKey base64-encoded DSA public key + * @return a native Java DSAPublicKey + * @throws KeyException thrown if there is an error constructing key + */ + public static DSAPublicKey buildJavaDSAPublicKey(String base64EncodedKey) throws KeyException { + X509EncodedKeySpec keySpec = new X509EncodedKeySpec(Base64.decode(base64EncodedKey)); + return (DSAPublicKey) buildKey(keySpec, "DSA"); + } + + /** + * Build Java RSA public key from base64 encoding. + * + * @param base64EncodedKey base64-encoded RSA public key + * @return a native Java RSAPublicKey + * @throws KeyException thrown if there is an error constructing key + */ + public static RSAPublicKey buildJavaRSAPublicKey(String base64EncodedKey) throws KeyException { + X509EncodedKeySpec keySpec = new X509EncodedKeySpec(Base64.decode(base64EncodedKey)); + return (RSAPublicKey) buildKey(keySpec, "RSA"); + } + + /** + * Build Java EC public key from base64 encoding. + * + * @param base64EncodedKey base64-encoded EC public key + * @return a native Java ECPublicKey + * @throws KeyException thrown if there is an error constructing key + */ + public static ECPublicKey buildJavaECPublicKey(String base64EncodedKey) throws KeyException { + X509EncodedKeySpec keySpec = new X509EncodedKeySpec(Base64.decode(base64EncodedKey)); + return (ECPublicKey) buildKey(keySpec, "EC"); + } + + /** + * Build Java RSA private key from base64 encoding. + * + * @param base64EncodedKey base64-encoded RSA private key + * @return a native Java RSAPrivateKey + * @throws KeyException thrown if there is an error constructing key + */ + public static RSAPrivateKey buildJavaRSAPrivateKey(String base64EncodedKey) throws KeyException { + PrivateKey key = buildJavaPrivateKey(base64EncodedKey); + if (! (key instanceof RSAPrivateKey)) { + throw new KeyException("Generated key was not an RSAPrivateKey instance"); + } + return (RSAPrivateKey) key; + } + + /** + * Build Java DSA private key from base64 encoding. + * + * @param base64EncodedKey base64-encoded DSA private key + * @return a native Java DSAPrivateKey + * @throws KeyException thrown if there is an error constructing key + */ + public static DSAPrivateKey buildJavaDSAPrivateKey(String base64EncodedKey) throws KeyException { + PrivateKey key = buildJavaPrivateKey(base64EncodedKey); + if (! (key instanceof DSAPrivateKey)) { + throw new KeyException("Generated key was not a DSAPrivateKey instance"); + } + return (DSAPrivateKey) key; + } + + /** + * Build Java private key from base64 encoding. The key should have no password. + * + * @param base64EncodedKey base64-encoded private key + * @return a native Java PrivateKey + * @throws KeyException thrown if there is an error constructing key + */ + public static PrivateKey buildJavaPrivateKey(String base64EncodedKey) throws KeyException { + return SecurityHelper.decodePrivateKey(Base64.decode(base64EncodedKey), null); + } + + /** + * Generates a public key from the given key spec. + * + * @param keySpec {@link KeySpec} specification for the key + * @param keyAlgorithm key generation algorithm, only DSA and RSA supported + * + * @return the generated {@link PublicKey} + * + * @throws KeyException thrown if the key algorithm is not supported by the JCE or the key spec does not + * contain valid information + */ + public static PublicKey buildKey(KeySpec keySpec, String keyAlgorithm) throws KeyException { + try { + KeyFactory keyFactory = KeyFactory.getInstance(keyAlgorithm); + return keyFactory.generatePublic(keySpec); + } catch (NoSuchAlgorithmException e) { + throw new KeyException(keyAlgorithm + "algorithm is not supported by the JCE", e); + } catch (InvalidKeySpecException e) { + throw new KeyException("Invalid key information", e); + } + } + + /** + * Randomly generates a Java JCE symmetric Key object from the specified XML Encryption algorithm URI. + * + * @param algoURI The XML Encryption algorithm URI + * @return a randomly-generated symmteric key + * @throws NoSuchProviderException provider not found + * @throws NoSuchAlgorithmException algorithm not found + */ + public static SecretKey generateKeyFromURI(String algoURI) + throws NoSuchAlgorithmException, NoSuchProviderException { + String jceAlgorithmName = JCEMapper.getJCEKeyAlgorithmFromURI(algoURI); + int keyLength = JCEMapper.getKeyLengthFromURI(algoURI); + return generateKey(jceAlgorithmName, keyLength, null); + } + + /** + * Randomly generates a Java JCE KeyPair object from the specified XML Encryption algorithm URI. + * + * @param algoURI The XML Encryption algorithm URI + * @param keyLength the length of key to generate + * @return a randomly-generated KeyPair + * @throws NoSuchProviderException provider not found + * @throws NoSuchAlgorithmException algorithm not found + */ + public static KeyPair generateKeyPairFromURI(String algoURI, int keyLength) + throws NoSuchAlgorithmException, NoSuchProviderException { + String jceAlgorithmName = JCEMapper.getJCEKeyAlgorithmFromURI(algoURI); + return generateKeyPair(jceAlgorithmName, keyLength, null); + } + + /** + * Generate a random symmetric key. + * + * @param algo key algorithm + * @param keyLength key length + * @param provider JCA provider + * @return randomly generated symmetric key + * @throws NoSuchAlgorithmException algorithm not found + * @throws NoSuchProviderException provider not found + */ + public static SecretKey generateKey(String algo, int keyLength, String provider) + throws NoSuchAlgorithmException, NoSuchProviderException { + SecretKey key = null; + KeyGenerator keyGenerator = null; + if (provider != null) { + keyGenerator = KeyGenerator.getInstance(algo, provider); + } else { + keyGenerator = KeyGenerator.getInstance(algo); + } + keyGenerator.init(keyLength); + key = keyGenerator.generateKey(); + return key; + } + + /** + * Generate a random asymmetric key pair. + * + * @param algo key algorithm + * @param keyLength key length + * @param provider JCA provider + * @return randomly generated key + * @throws NoSuchAlgorithmException algorithm not found + * @throws NoSuchProviderException provider not found + */ + public static KeyPair generateKeyPair(String algo, int keyLength, String provider) + throws NoSuchAlgorithmException, NoSuchProviderException { + KeyPairGenerator keyGenerator = null; + if (provider != null) { + keyGenerator = KeyPairGenerator.getInstance(algo, provider); + } else { + keyGenerator = KeyPairGenerator.getInstance(algo); + } + keyGenerator.initialize(keyLength); + return keyGenerator.generateKeyPair(); + } + + /** + * Generate a random symmetric key and return in a BasicCredential. + * + * @param algorithmURI The XML Encryption algorithm URI + * @return a basic credential containing a randomly generated symmetric key + * @throws NoSuchAlgorithmException algorithm not found + * @throws NoSuchProviderException provider not found + */ + public static Credential generateKeyAndCredential(String algorithmURI) + throws NoSuchAlgorithmException, NoSuchProviderException { + SecretKey key = generateKeyFromURI(algorithmURI); + BasicCredential credential = new BasicCredential(); + credential.setSecretKey(key); + return credential; + } + + /** + * Generate a random asymmetric key pair and return in a BasicCredential. + * + * @param algorithmURI The XML Encryption algorithm URI + * @param keyLength key length + * @param includePrivate if true, the private key will be included as well + * @return a basic credential containing a randomly generated asymmetric key pair + * @throws NoSuchAlgorithmException algorithm not found + * @throws NoSuchProviderException provider not found + */ + public static Credential generateKeyPairAndCredential(String algorithmURI, int keyLength, boolean includePrivate) + throws NoSuchAlgorithmException, NoSuchProviderException { + KeyPair keyPair = generateKeyPairFromURI(algorithmURI, keyLength); + BasicCredential credential = new BasicCredential(); + credential.setPublicKey(keyPair.getPublic()); + if (includePrivate) { + credential.setPrivateKey(keyPair.getPrivate()); + } + return credential; + } + + /** + * Get a basic KeyInfo credential resolver which can process standard inline + * data - RSAKeyValue, DSAKeyValue, X509Data. + * + * @return a new KeyInfoCredentialResolver instance + */ + public static KeyInfoCredentialResolver buildBasicInlineKeyInfoResolver() { + List providers = new ArrayList(); + providers.add( new RSAKeyValueProvider() ); + providers.add( new DSAKeyValueProvider() ); + providers.add( new InlineX509DataProvider() ); + return new BasicProviderKeyInfoCredentialResolver(providers); + } + + /** + * Compare the supplied public and private keys, and determine if they correspond to the same key pair. + * + * @param pubKey the public key + * @param privKey the private key + * @return true if the public and private are from the same key pair, false if not + * @throws SecurityException if the keys can not be evaluated, or if the key algorithm is unsupported or unknown + */ + public static boolean matchKeyPair(PublicKey pubKey, PrivateKey privKey) throws SecurityException { + Logger log = getLogger(); + // This approach attempts to match the keys by signing and then validating some known data. + + if (pubKey == null || privKey == null) { + throw new SecurityException("Either public or private key was null"); + } + + // Need to dynamically determine the JCA signature algorithm ID to use from the key algorithm. + // Don't currently have a direct mapping, so have to map to XML Signature algorithm URI first, + // then map that to JCA algorithm ID. + SecurityConfiguration secConfig = Configuration.getGlobalSecurityConfiguration(); + if (secConfig == null) { + throw new SecurityException("Global security configuration was null, could not resolve signing algorithm"); + } + String algoURI = secConfig.getSignatureAlgorithmURI(privKey.getAlgorithm()); + if (algoURI == null) { + throw new SecurityException("Can't determine algorithm URI from key algorithm: " + privKey.getAlgorithm()); + } + String jcaAlgoID = getAlgorithmIDFromURI(algoURI); + if (jcaAlgoID == null) { + throw new SecurityException("Can't determine JCA algorithm ID from algorithm URI: " + algoURI); + } + + if (log.isDebugEnabled()) { + log.debug("Attempting to match key pair containing key algorithms public '{}' private '{}', " + + "using JCA signature algorithm '{}'", new Object[] { pubKey.getAlgorithm(), + privKey.getAlgorithm(), jcaAlgoID, }); + } + + byte[] data = "This is the data to sign".getBytes(); + byte[] signature = SigningUtil.sign(privKey, jcaAlgoID, data); + return SigningUtil.verify(pubKey, jcaAlgoID, signature, data); + } + + /** + * Prepare a {@link Signature} with necessary additional information prior to signing. + * + *

+ * NOTE:Since this operation modifies the specified Signature object, it should be called + * prior to marshalling the Signature object. + *

+ * + *

+ * The following Signature values will be added: + *

    + *
  • signature algorithm URI
  • + *
  • canonicalization algorithm URI
  • + *
  • HMAC output length (if applicable and a value is configured)
  • + *
  • a {@link KeyInfo} element representing the signing credential
  • + *
+ *

+ * + *

+ * Existing (non-null) values of these parameters on the specified signature will NOT be + * overwritten, however. + *

+ * + *

+ * All values are determined by the specified {@link SecurityConfiguration}. If a security configuration is not + * supplied, the global security configuration ({@link Configuration#getGlobalSecurityConfiguration()}) will be + * used. + *

+ * + *

+ * The signature algorithm URI and optional HMAC output length are derived from the signing credential. + *

+ * + *

+ * The KeyInfo to be generated is based on the {@link NamedKeyInfoGeneratorManager} defined in the security + * configuration, and is determined by the type of the signing credential and an optional KeyInfo generator manager + * name. If the latter is ommited, the default manager ({@link NamedKeyInfoGeneratorManager#getDefaultManager()}) + * of the security configuration's named generator manager will be used. + *

+ * + * @param signature the Signature to be updated + * @param signingCredential the credential with which the Signature will be computed + * @param config the SecurityConfiguration to use (may be null) + * @param keyInfoGenName the named KeyInfoGeneratorManager configuration to use (may be null) + * @throws SecurityException thrown if there is an error generating the KeyInfo from the signing credential + */ + public static void prepareSignatureParams(Signature signature, Credential signingCredential, + SecurityConfiguration config, String keyInfoGenName) throws SecurityException { + Logger log = getLogger(); + + SecurityConfiguration secConfig; + if (config != null) { + secConfig = config; + } else { + secConfig = Configuration.getGlobalSecurityConfiguration(); + } + + // The algorithm URI is derived from the credential + String signAlgo = signature.getSignatureAlgorithm(); + if (signAlgo == null) { + signAlgo = secConfig.getSignatureAlgorithmURI(signingCredential); + signature.setSignatureAlgorithm(signAlgo); + } + + // If we're doing HMAC, set the output length + if (SecurityHelper.isHMAC(signAlgo)) { + if (signature.getHMACOutputLength() == null) { + signature.setHMACOutputLength(secConfig.getSignatureHMACOutputLength()); + } + } + + if (signature.getCanonicalizationAlgorithm() == null) { + signature.setCanonicalizationAlgorithm(secConfig.getSignatureCanonicalizationAlgorithm()); + } + + if (signature.getKeyInfo() == null) { + KeyInfoGenerator kiGenerator = getKeyInfoGenerator(signingCredential, secConfig, keyInfoGenName); + if (kiGenerator != null) { + try { + KeyInfo keyInfo = kiGenerator.generate(signingCredential); + signature.setKeyInfo(keyInfo); + } catch (SecurityException e) { + log.error("Error generating KeyInfo from credential", e); + throw e; + } + } else { + log.info("No factory for named KeyInfoGenerator {} was found for credential type {}", keyInfoGenName, + signingCredential.getCredentialType().getName()); + log.info("No KeyInfo will be generated for Signature"); + } + } + } + + /** + * Build an instance of {@link EncryptionParameters} suitable for passing to an + * {@link org.opensaml.xml.encryption.Encrypter}. + * + *

+ * The following parameter values will be added: + *

    + *
  • the encryption credential (optional)
  • + *
  • encryption algorithm URI
  • + *
  • an appropriate {@link KeyInfoGenerator} instance which will be used to generate a {@link KeyInfo} element + * from the encryption credential
  • + *
+ *

+ * + *

+ * All values are determined by the specified {@link SecurityConfiguration}. If a security configuration is not + * supplied, the global security configuration ({@link Configuration#getGlobalSecurityConfiguration()}) will be + * used. + *

+ * + *

+ * The encryption algorithm URI is derived from the optional supplied encryption credential. If omitted, the value + * of {@link SecurityConfiguration#getAutoGeneratedDataEncryptionKeyAlgorithmURI()} will be used. + *

+ * + *

+ * The KeyInfoGenerator to be used is based on the {@link NamedKeyInfoGeneratorManager} defined in the security + * configuration, and is determined by the type of the signing credential and an optional KeyInfo generator manager + * name. If the latter is ommited, the default manager ({@link NamedKeyInfoGeneratorManager#getDefaultManager()}) + * of the security configuration's named generator manager will be used. + *

+ * + * @param encryptionCredential the credential with which the data will be encrypted (may be null) + * @param config the SecurityConfiguration to use (may be null) + * @param keyInfoGenName the named KeyInfoGeneratorManager configuration to use (may be null) + * @return a new instance of EncryptionParameters + */ + public static EncryptionParameters buildDataEncryptionParams(Credential encryptionCredential, + SecurityConfiguration config, String keyInfoGenName) { + Logger log = getLogger(); + + SecurityConfiguration secConfig; + if (config != null) { + secConfig = config; + } else { + secConfig = Configuration.getGlobalSecurityConfiguration(); + } + + EncryptionParameters encParams = new EncryptionParameters(); + encParams.setEncryptionCredential(encryptionCredential); + + if (encryptionCredential == null) { + encParams.setAlgorithm(secConfig.getAutoGeneratedDataEncryptionKeyAlgorithmURI()); + } else { + encParams.setAlgorithm(secConfig.getDataEncryptionAlgorithmURI(encryptionCredential)); + + KeyInfoGenerator kiGenerator = getKeyInfoGenerator(encryptionCredential, secConfig, keyInfoGenName); + if (kiGenerator != null) { + encParams.setKeyInfoGenerator(kiGenerator); + } else { + log.info("No factory for named KeyInfoGenerator {} was found for credential type{}", keyInfoGenName, + encryptionCredential.getCredentialType().getName()); + log.info("No KeyInfo will be generated for EncryptedData"); + } + } + + return encParams; + } + + /** + * Build an instance of {@link KeyEncryptionParameters} suitable for passing to an + * {@link org.opensaml.xml.encryption.Encrypter}. + * + *

+ * The following parameter values will be added: + *

    + *
  • the key encryption credential
  • + *
  • key transport encryption algorithm URI
  • + *
  • an appropriate {@link KeyInfoGenerator} instance which will be used to generate a {@link KeyInfo} element + * from the key encryption credential
  • + *
  • intended recipient of the resultant encrypted key (optional)
  • + *
+ *

+ * + *

+ * All values are determined by the specified {@link SecurityConfiguration}. If a security configuration is not + * supplied, the global security configuration ({@link Configuration#getGlobalSecurityConfiguration()}) will be + * used. + *

+ * + *

+ * The encryption algorithm URI is derived from the optional supplied encryption credential. If omitted, the value + * of {@link SecurityConfiguration#getAutoGeneratedDataEncryptionKeyAlgorithmURI()} will be used. + *

+ * + *

+ * The KeyInfoGenerator to be used is based on the {@link NamedKeyInfoGeneratorManager} defined in the security + * configuration, and is determined by the type of the signing credential and an optional KeyInfo generator manager + * name. If the latter is ommited, the default manager ({@link NamedKeyInfoGeneratorManager#getDefaultManager()}) + * of the security configuration's named generator manager will be used. + *

+ * + * @param encryptionCredential the credential with which the key will be encrypted + * @param wrappedKeyAlgorithm the JCA key algorithm name of the key to be encrypted (may be null) + * @param config the SecurityConfiguration to use (may be null) + * @param keyInfoGenName the named KeyInfoGeneratorManager configuration to use (may be null) + * @param recipient the intended recipient of the resultant encrypted key, typically the owner of the key encryption + * key (may be null) + * @return a new instance of KeyEncryptionParameters + * @throws SecurityException if encryption credential is not supplied + * + */ + public static KeyEncryptionParameters buildKeyEncryptionParams(Credential encryptionCredential, + String wrappedKeyAlgorithm, SecurityConfiguration config, String keyInfoGenName, String recipient) + throws SecurityException { + Logger log = getLogger(); + + SecurityConfiguration secConfig; + if (config != null) { + secConfig = config; + } else { + secConfig = Configuration.getGlobalSecurityConfiguration(); + } + + KeyEncryptionParameters kekParams = new KeyEncryptionParameters(); + kekParams.setEncryptionCredential(encryptionCredential); + + if (encryptionCredential == null) { + throw new SecurityException("Key encryption credential may not be null"); + } + + kekParams.setAlgorithm(secConfig.getKeyTransportEncryptionAlgorithmURI(encryptionCredential, + wrappedKeyAlgorithm)); + + KeyInfoGenerator kiGenerator = getKeyInfoGenerator(encryptionCredential, secConfig, keyInfoGenName); + if (kiGenerator != null) { + kekParams.setKeyInfoGenerator(kiGenerator); + } else { + log.info("No factory for named KeyInfoGenerator {} was found for credential type {}", keyInfoGenName, + encryptionCredential.getCredentialType().getName()); + log.info("No KeyInfo will be generated for EncryptedKey"); + } + + kekParams.setRecipient(recipient); + + return kekParams; + } + + /** + * Obtains a {@link KeyInfoGenerator} for the specified {@link Credential}. + * + *

+ * The KeyInfoGenerator returned is based on the {@link NamedKeyInfoGeneratorManager} defined by the specified + * security configuration via {@link SecurityConfiguration#getKeyInfoGeneratorManager()}, and is determined by the + * type of the signing credential and an optional KeyInfo generator manager name. If the latter is ommited, the + * default manager ({@link NamedKeyInfoGeneratorManager#getDefaultManager()}) of the security configuration's + * named generator manager will be used. + *

+ * + *

+ * The generator is determined by the specified {@link SecurityConfiguration}. If a security configuration is not + * supplied, the global security configuration ({@link Configuration#getGlobalSecurityConfiguration()}) will be + * used. + *

+ * + * @param credential the credential for which a generator is desired + * @param config the SecurityConfiguration to use (may be null) + * @param keyInfoGenName the named KeyInfoGeneratorManager configuration to use (may be null) + * @return a KeyInfoGenerator appropriate for the specified credential + */ + public static KeyInfoGenerator getKeyInfoGenerator(Credential credential, SecurityConfiguration config, + String keyInfoGenName) { + + SecurityConfiguration secConfig; + if (config != null) { + secConfig = config; + } else { + secConfig = Configuration.getGlobalSecurityConfiguration(); + } + + NamedKeyInfoGeneratorManager kiMgr = secConfig.getKeyInfoGeneratorManager(); + if (kiMgr != null) { + KeyInfoGeneratorFactory kiFactory = null; + if (DatatypeHelper.isEmpty(keyInfoGenName)) { + kiFactory = kiMgr.getDefaultManager().getFactory(credential); + } else { + kiFactory = kiMgr.getFactory(keyInfoGenName, credential); + } + if (kiFactory != null) { + return kiFactory.newInstance(); + } + } + return null; + } + + /** + * Get an SLF4J Logger. + * + * @return a Logger instance + */ + private static Logger getLogger() { + return LoggerFactory.getLogger(SecurityHelper.class); + } + + static { + // We use some Apache XML Security utility functions, so need to make sure library + // is initialized. + if (!Init.isInitialized()) { + Init.init(); + } + + // Additonal algorithm URI to JCA key algorithm mappins, beyond what is currently + // supplied in the Apache XML Security mapper config. + dsaAlgorithmURIs = new LazySet(); + dsaAlgorithmURIs.add(SignatureConstants.ALGO_ID_SIGNATURE_DSA); + + ecdsaAlgorithmURIs = new LazySet(); + ecdsaAlgorithmURIs.add(SignatureConstants.ALGO_ID_SIGNATURE_ECDSA_SHA1); + + rsaAlgorithmURIs = new HashSet(10); + rsaAlgorithmURIs.add(SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA1); + rsaAlgorithmURIs.add(SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA256); + rsaAlgorithmURIs.add(SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA384); + rsaAlgorithmURIs.add(SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA512); + rsaAlgorithmURIs.add(SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA512); + rsaAlgorithmURIs.add(SignatureConstants.ALGO_ID_SIGNATURE_RSA_RIPEMD160); + rsaAlgorithmURIs.add(SignatureConstants.ALGO_ID_SIGNATURE_NOT_RECOMMENDED_RSA_MD5); + } +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/security/SecurityTestHelper.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/security/SecurityTestHelper.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/security/SecurityTestHelper.java 17 Aug 2012 15:17:19 -0000 1.1 @@ -0,0 +1,251 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.security; + +import java.security.KeyException; +import java.security.KeyPair; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.cert.CRLException; +import java.security.cert.CertificateException; +import java.security.interfaces.DSAPrivateKey; +import java.security.interfaces.DSAPublicKey; +import java.security.interfaces.RSAPrivateKey; +import java.security.interfaces.RSAPublicKey; +import java.security.spec.KeySpec; + +import javax.crypto.SecretKey; + +import org.opensaml.xml.security.credential.Credential; +import org.opensaml.xml.security.keyinfo.KeyInfoCredentialResolver; + +/** + * @deprecated + * Some utility methods for doing security, credential, key and crypto-related tests. + */ +public final class SecurityTestHelper { + + /** Constructor. */ + private SecurityTestHelper() { } + + /** + * @deprecated + * Build Java certificate from base64 encoding. + * + * @param base64Cert base64-encoded certificate + * @return a native Java X509 certificate + * @throws CertificateException thrown if there is an error constructing certificate + */ + public static java.security.cert.X509Certificate buildJavaX509Cert(String base64Cert) throws CertificateException { + return SecurityHelper.buildJavaX509Cert(base64Cert); + } + + /** + * @deprecated + * Build Java CRL from base64 encoding. + * + * @param base64CRL base64-encoded CRL + * @return a native Java X509 CRL + * @throws CertificateException thrown if there is an error constructing certificate + * @throws CRLException thrown if there is an error constructing CRL + */ + public static java.security.cert.X509CRL buildJavaX509CRL(String base64CRL) + throws CertificateException, CRLException { + return SecurityHelper.buildJavaX509CRL(base64CRL); + } + + /** + * @deprecated + * Build Java DSA public key from base64 encoding. + * + * @param base64EncodedKey base64-encoded DSA public key + * @return a native Java DSAPublicKey + * @throws KeyException thrown if there is an error constructing key + */ + public static DSAPublicKey buildJavaDSAPublicKey(String base64EncodedKey) throws KeyException { + return SecurityHelper.buildJavaDSAPublicKey(base64EncodedKey); + } + + /** + * @deprecated + * Build Java RSA public key from base64 encoding. + * + * @param base64EncodedKey base64-encoded RSA public key + * @return a native Java RSAPublicKey + * @throws KeyException thrown if there is an error constructing key + */ + public static RSAPublicKey buildJavaRSAPublicKey(String base64EncodedKey) throws KeyException { + return SecurityHelper.buildJavaRSAPublicKey(base64EncodedKey); + } + + /** + * @deprecated + * Build Java RSA private key from base64 encoding. + * + * @param base64EncodedKey base64-encoded RSA private key + * @return a native Java RSAPrivateKey + * @throws KeyException thrown if there is an error constructing key + */ + public static RSAPrivateKey buildJavaRSAPrivateKey(String base64EncodedKey) throws KeyException { + return SecurityHelper.buildJavaRSAPrivateKey(base64EncodedKey); + } + + /** + * @deprecated + * Build Java DSA private key from base64 encoding. + * + * @param base64EncodedKey base64-encoded DSA private key + * @return a native Java DSAPrivateKey + * @throws KeyException thrown if there is an error constructing key + */ + public static DSAPrivateKey buildJavaDSAPrivateKey(String base64EncodedKey) throws KeyException { + return SecurityHelper.buildJavaDSAPrivateKey(base64EncodedKey); + } + + /** + * @deprecated + * Build Java private key from base64 encoding. The key should have no password. + * + * @param base64EncodedKey base64-encoded private key + * @return a native Java PrivateKey + * @throws KeyException thrown if there is an error constructing key + */ + public static PrivateKey buildJavaPrivateKey(String base64EncodedKey) throws KeyException { + return SecurityHelper.buildJavaPrivateKey(base64EncodedKey); + } + + /** + * @deprecated + * Generates a public key from the given key spec. + * + * @param keySpec {@link KeySpec} specification for the key + * @param keyAlgorithm key generation algorithm, only DSA and RSA supported + * + * @return the generated {@link PublicKey} + * + * @throws KeyException thrown if the key algorithm is not supported by the JCE or the key spec does not + * contain valid information + */ + public static PublicKey buildKey(KeySpec keySpec, String keyAlgorithm) throws KeyException { + return SecurityHelper.buildKey(keySpec, keyAlgorithm); + } + + /** + * @deprecated + * Randomly generates a Java JCE symmetric Key object from the specified XML Encryption algorithm URI. + * + * @param algoURI The XML Encryption algorithm URI + * @return a randomly-generated symmteric key + * @throws NoSuchProviderException provider not found + * @throws NoSuchAlgorithmException algorithm not found + */ + public static SecretKey generateKeyFromURI(String algoURI) + throws NoSuchAlgorithmException, NoSuchProviderException { + return SecurityHelper.generateKeyFromURI(algoURI); + } + + /** + * @deprecated + * Randomly generates a Java JCE KeyPair object from the specified XML Encryption algorithm URI. + * + * @param algoURI The XML Encryption algorithm URI + * @param keyLength the length of key to generate + * @return a randomly-generated KeyPair + * @throws NoSuchProviderException provider not found + * @throws NoSuchAlgorithmException algorithm not found + */ + public static KeyPair generateKeyPairFromURI(String algoURI, int keyLength) + throws NoSuchAlgorithmException, NoSuchProviderException { + return SecurityHelper.generateKeyPairFromURI(algoURI, keyLength); + } + + /** + * @deprecated + * Generate a random symmetric key. + * + * @param algo key algorithm + * @param keyLength key length + * @param provider JCA provider + * @return randomly generated symmetric key + * @throws NoSuchAlgorithmException algorithm not found + * @throws NoSuchProviderException provider not found + */ + public static SecretKey generateKey(String algo, int keyLength, String provider) + throws NoSuchAlgorithmException, NoSuchProviderException { + return SecurityHelper.generateKey(algo, keyLength, provider); + } + + /** + * @deprecated + * Generate a random asymmetric key pair. + * + * @param algo key algorithm + * @param keyLength key length + * @param provider JCA provider + * @return randomly generated key + * @throws NoSuchAlgorithmException algorithm not found + * @throws NoSuchProviderException provider not found + */ + public static KeyPair generateKeyPair(String algo, int keyLength, String provider) + throws NoSuchAlgorithmException, NoSuchProviderException { + return SecurityHelper.generateKeyPair(algo, keyLength, provider); + } + + /** + * @deprecated + * Generate a random symmetric key and return in a BasicCredential. + * + * @param algorithmURI The XML Encryption algorithm URI + * @return a basic credential containing a randomly generated symmetric key + * @throws NoSuchAlgorithmException algorithm not found + * @throws NoSuchProviderException provider not found + */ + public static Credential generateKeyAndCredential(String algorithmURI) + throws NoSuchAlgorithmException, NoSuchProviderException { + return SecurityHelper.generateKeyAndCredential(algorithmURI); + } + + /** + * @deprecated + * Generate a random asymmetric key pair and return in a BasicCredential. + * + * @param algorithmURI The XML Encryption algorithm URI + * @param keyLength key length + * @param includePrivate if true, the private key will be included as well + * @return a basic credential containing a randomly generated asymmetric key pair + * @throws NoSuchAlgorithmException algorithm not found + * @throws NoSuchProviderException provider not found + */ + public static Credential generateKeyPairAndCredential(String algorithmURI, int keyLength, boolean includePrivate) + throws NoSuchAlgorithmException, NoSuchProviderException { + return SecurityHelper.generateKeyPairAndCredential(algorithmURI, keyLength, includePrivate); + } + + /** + * @deprecated + * Get a basic KeyInfo credential resolver which can process standard inline + * data - RSAKeyValue, DSAKeyValue, X509Data. + * + * @return a new KeyInfoCredentialResolver instance + */ + public static KeyInfoCredentialResolver buildBasicInlineKeyInfoResolver() { + return SecurityHelper.buildBasicInlineKeyInfoResolver(); + } +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/security/SigningUtil.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/security/SigningUtil.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/security/SigningUtil.java 17 Aug 2012 15:17:19 -0000 1.1 @@ -0,0 +1,292 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.security; + +import java.security.GeneralSecurityException; +import java.security.Key; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.Signature; +import java.util.Arrays; + +import javax.crypto.Mac; + +import org.bouncycastle.util.encoders.Hex; +import org.opensaml.xml.security.credential.Credential; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * A utility class for computing and verifying raw signatures and MAC values. + */ +public final class SigningUtil { + + /** Constructor. */ + private SigningUtil() { + } + + /** + * Compute the signature or MAC value over the supplied input. + * + * It is up to the caller to ensure that the specified algorithm URI is consistent with the type of signing key + * supplied in the signing credential. + * + * @param signingCredential the credential containing the signing key + * @param algorithmURI the algorithm URI to use + * @param input the input over which to compute the signature + * @return the computed signature or MAC value + * @throws SecurityException throw if the computation process results in an error + */ + public static byte[] signWithURI(Credential signingCredential, String algorithmURI, byte[] input) + throws SecurityException { + + String jcaAlgorithmID = SecurityHelper.getAlgorithmIDFromURI(algorithmURI); + if (jcaAlgorithmID == null) { + throw new SecurityException("Could not derive JCA algorithm identifier from algorithm URI"); + } + + boolean isHMAC = SecurityHelper.isHMAC(algorithmURI); + + return sign(signingCredential, jcaAlgorithmID, isHMAC, input); + } + + /** + * Compute the signature or MAC value over the supplied input. + * + * It is up to the caller to ensure that the specified algorithm ID and isMAC flag are consistent with the type of + * signing key supplied in the signing credential. + * + * @param signingCredential the credential containing the signing key + * @param jcaAlgorithmID the Java JCA algorithm ID to use + * @param isMAC flag indicating whether the operation to be performed is a signature or MAC computation + * @param input the input over which to compute the signature + * @return the computed signature or MAC value + * @throws SecurityException throw if the computation process results in an error + */ + public static byte[] sign(Credential signingCredential, String jcaAlgorithmID, boolean isMAC, byte[] input) + throws SecurityException { + Logger log = getLogger(); + + Key signingKey = SecurityHelper.extractSigningKey(signingCredential); + if (signingKey == null) { + log.error("No signing key supplied in signing credential for signature computation"); + throw new SecurityException("No signing key supplied in signing credential"); + } + + if (isMAC) { + return signMAC(signingKey, jcaAlgorithmID, input); + } else if (signingKey instanceof PrivateKey) { + return sign((PrivateKey) signingKey, jcaAlgorithmID, input); + } else { + log.error("No PrivateKey present in signing credential for signature computation"); + throw new SecurityException("No PrivateKey supplied for signing"); + } + } + + /** + * Compute the raw signature value over the supplied input. + * + * It is up to the caller to ensure that the specified algorithm ID is consistent with the type of signing key + * supplied. + * + * @param signingKey the private key with which to compute the signature + * @param jcaAlgorithmID the Java JCA algorithm ID to use + * @param input the input over which to compute the signature + * @return the computed signature value + * @throws SecurityException thrown if the signature computation results in an error + */ + public static byte[] sign(PrivateKey signingKey, String jcaAlgorithmID, byte[] input) throws SecurityException { + Logger log = getLogger(); + log.debug("Computing signature over input using private key of type {} and JCA algorithm ID {}", signingKey + .getAlgorithm(), jcaAlgorithmID); + + try { + Signature signature = Signature.getInstance(jcaAlgorithmID); + signature.initSign(signingKey); + signature.update(input); + byte[] rawSignature = signature.sign(); + log.debug("Computed signature: {}", new String(Hex.encode(rawSignature))); + return rawSignature; + } catch (GeneralSecurityException e) { + log.error("Error during signature generation", e); + throw new SecurityException("Error during signature generation", e); + } + } + + /** + * Compute the Message Authentication Code (MAC) value over the supplied input. + * + * It is up to the caller to ensure that the specified algorithm ID is consistent with the type of signing key + * supplied. + * + * @param signingKey the key with which to compute the MAC + * @param jcaAlgorithmID the Java JCA algorithm ID to use + * @param input the input over which to compute the MAC + * @return the computed MAC value + * @throws SecurityException thrown if the MAC computation results in an error + */ + public static byte[] signMAC(Key signingKey, String jcaAlgorithmID, byte[] input) throws SecurityException { + Logger log = getLogger(); + log.debug("Computing MAC over input using key of type {} and JCA algorithm ID {}", signingKey.getAlgorithm(), + jcaAlgorithmID); + + try { + Mac mac = Mac.getInstance(jcaAlgorithmID); + mac.init(signingKey); + mac.update(input); + byte[] rawMAC = mac.doFinal(); + log.debug("Computed MAC: {}", new String(Hex.encode(rawMAC))); + return rawMAC; + } catch (GeneralSecurityException e) { + log.error("Error during MAC generation", e); + throw new SecurityException("Error during MAC generation", e); + } + } + + /** + * Verify the signature value computed over the supplied input against the supplied signature value. + * + * It is up to the caller to ensure that the specified algorithm URI are consistent with the type of verification + * credential supplied. + * + * @param verificationCredential the credential containing the verification key + * @param algorithmURI the algorithm URI to use + * @param signature the computed signature value received from the signer + * @param input the input over which the signature is computed and verified + * @return true if the signature value computed over the input using the supplied key and algorithm ID is identical + * to the supplied signature value + * @throws SecurityException thrown if the signature computation or verification process results in an error + */ + public static boolean verifyWithURI(Credential verificationCredential, String algorithmURI, byte[] signature, + byte[] input) throws SecurityException { + + String jcaAlgorithmID = SecurityHelper.getAlgorithmIDFromURI(algorithmURI); + if (jcaAlgorithmID == null) { + throw new SecurityException("Could not derive JCA algorithm identifier from algorithm URI"); + } + + boolean isHMAC = SecurityHelper.isHMAC(algorithmURI); + + return verify(verificationCredential, jcaAlgorithmID, isHMAC, signature, input); + } + + /** + * Verify the signature value computed over the supplied input against the supplied signature value. + * + * It is up to the caller to ensure that the specified algorithm ID and isMAC flag are consistent with the type of + * verification credential supplied. + * + * @param verificationCredential the credential containing the verification key + * @param jcaAlgorithmID the Java JCA algorithm ID to use + * @param isMAC flag indicating whether the operation to be performed is a signature or MAC computation + * @param signature the computed signature value received from the signer + * @param input the input over which the signature is computed and verified + * @return true if the signature value computed over the input using the supplied key and algorithm ID is identical + * to the supplied signature value + * @throws SecurityException thrown if the signature computation or verification process results in an error + */ + public static boolean verify(Credential verificationCredential, String jcaAlgorithmID, boolean isMAC, + byte[] signature, byte[] input) throws SecurityException { + Logger log = getLogger(); + + Key verificationKey = SecurityHelper.extractVerificationKey(verificationCredential); + if (verificationKey == null) { + log.error("No verification key supplied in verification credential for signature verification"); + throw new SecurityException("No verification key supplied in verification credential"); + } + + if (isMAC) { + return verifyMAC(verificationKey, jcaAlgorithmID, signature, input); + } else if (verificationKey instanceof PublicKey) { + return verify((PublicKey) verificationKey, jcaAlgorithmID, signature, input); + } else { + log.error("No PublicKey present in verification credential for signature verification"); + throw new SecurityException("No PublicKey supplied for signature verification"); + } + } + + /** + * Verify the signature value computed over the supplied input against the supplied signature value. + * + * It is up to the caller to ensure that the specified algorithm ID is consistent with the type of verification key + * supplied. + * + * @param verificationKey the key with which to compute and verify the signature + * @param jcaAlgorithmID the Java JCA algorithm ID to use + * @param signature the computed signature value received from the signer + * @param input the input over which the signature is computed and verified + * @return true if the signature value computed over the input using the supplied key and algorithm ID is identical + * to the supplied signature value + * @throws SecurityException thrown if the signature computation or verification process results in an error + */ + public static boolean verify(PublicKey verificationKey, String jcaAlgorithmID, byte[] signature, byte[] input) + throws SecurityException { + Logger log = getLogger(); + + log.debug("Verifying signature over input using public key of type {} and JCA algorithm ID {}", verificationKey + .getAlgorithm(), jcaAlgorithmID); + + try { + Signature sig = Signature.getInstance(jcaAlgorithmID); + sig.initVerify(verificationKey); + sig.update(input); + return sig.verify(signature); + } catch (GeneralSecurityException e) { + log.error("Error during signature verification", e); + throw new SecurityException("Error during signature verification", e); + } + } + + /** + * Verify the Message Authentication Code (MAC) value computed over the supplied input against the supplied MAC + * value. + * + * It is up to the caller to ensure that the specified algorithm ID is consistent with the type of verification key + * supplied. + * + * @param verificationKey the key with which to compute and verify the MAC + * @param jcaAlgorithmID the Java JCA algorithm ID to use + * @param signature the computed MAC value received from the signer + * @param input the input over which the MAC is computed and verified + * @return true if the MAC value computed over the input using the supplied key and algorithm ID is identical to the + * supplied MAC signature value + * @throws SecurityException thrown if the MAC computation or verification process results in an error + */ + public static boolean verifyMAC(Key verificationKey, String jcaAlgorithmID, byte[] signature, byte[] input) + throws SecurityException { + Logger log = getLogger(); + + log.debug("Verifying MAC over input using key of type {} and JCA algorithm ID {}", verificationKey + .getAlgorithm(), jcaAlgorithmID); + + // Java JCA/JCE Mac interface doesn't have a verification op, + // so have to compute the Mac and compare the byte arrays manually. + + byte[] computed = signMAC(verificationKey, jcaAlgorithmID, input); + return Arrays.equals(computed, signature); + } + + /** + * Get an SLF4J Logger. + * + * @return a Logger instance + */ + private static Logger getLogger() { + return LoggerFactory.getLogger(SigningUtil.class); + } +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/security/package.html =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/security/package.html,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/security/package.html 17 Aug 2012 15:17:19 -0000 1.1 @@ -0,0 +1,5 @@ + + +Interfaces and classes used in representing cryptographic credentials, evaluating the trustworthiness of security of tokens, etc. + + \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/security/credential/AbstractCredential.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/security/credential/AbstractCredential.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/security/credential/AbstractCredential.java 17 Aug 2012 15:17:18 -0000 1.1 @@ -0,0 +1,94 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.security.credential; + +import java.security.PrivateKey; +import java.security.PublicKey; +import java.util.Collection; + +import javax.crypto.SecretKey; + +/** + * Base class for {@link org.opensaml.xml.security.credential.Credential} implementations. + */ +public abstract class AbstractCredential implements Credential { + + /** ID of the entity owning this credential. */ + protected String entityID; + + /** Usage type of this credential. */ + protected UsageType usageType; + + /** Key names for this credential. */ + protected Collection keyNames; + + /** Public key of this credential. */ + protected PublicKey publicKey; + + /** Secret key for this credential. */ + protected SecretKey secretKey; + + /** Private key of this credential. */ + protected PrivateKey privateKey; + + /** Credential context of this credential. */ + protected final CredentialContextSet credentialContextSet; + + /** + * Constructor. + */ + public AbstractCredential() { + credentialContextSet = new CredentialContextSet(); + } + + /** {@inheritDoc} */ + public String getEntityId() { + return entityID; + } + + /** {@inheritDoc} */ + public UsageType getUsageType() { + return usageType; + } + + /** {@inheritDoc} */ + public Collection getKeyNames() { + return keyNames; + } + + /** {@inheritDoc} */ + public PublicKey getPublicKey() { + return publicKey; + } + + /** {@inheritDoc} */ + public SecretKey getSecretKey() { + return secretKey; + } + + /** {@inheritDoc} */ + public PrivateKey getPrivateKey() { + return privateKey; + } + + /** {@inheritDoc} */ + public CredentialContextSet getCredentalContextSet() { + return credentialContextSet; + } + +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/security/credential/AbstractCredentialResolver.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/security/credential/AbstractCredentialResolver.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/security/credential/AbstractCredentialResolver.java 17 Aug 2012 15:17:17 -0000 1.1 @@ -0,0 +1,41 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.security.credential; + +import org.opensaml.xml.security.CriteriaSet; +import org.opensaml.xml.security.SecurityException; + +/** + * Abstract base class for {@link CredentialResolver} implementations. + */ +public abstract class AbstractCredentialResolver implements CredentialResolver { + + /** {@inheritDoc} */ + public Credential resolveSingle(CriteriaSet criteriaSet) throws SecurityException { + Iterable creds = resolve(criteriaSet); + if (creds.iterator().hasNext()) { + return creds.iterator().next(); + } else { + return null; + } + } + + /** {@inheritDoc} */ + public abstract Iterable resolve(CriteriaSet criteriaSet) throws SecurityException; + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/security/credential/AbstractCriteriaFilteringCredentialResolver.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/security/credential/AbstractCriteriaFilteringCredentialResolver.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/security/credential/AbstractCriteriaFilteringCredentialResolver.java 17 Aug 2012 15:17:18 -0000 1.1 @@ -0,0 +1,152 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.security.credential; + +import java.util.HashSet; +import java.util.Set; + +import org.opensaml.xml.security.Criteria; +import org.opensaml.xml.security.CriteriaFilteringIterable; +import org.opensaml.xml.security.CriteriaFilteringIterator; +import org.opensaml.xml.security.CriteriaSet; +import org.opensaml.xml.security.EvaluableCriteria; +import org.opensaml.xml.security.SecurityException; +import org.opensaml.xml.security.credential.criteria.EvaluableCredentialCriteria; +import org.opensaml.xml.security.credential.criteria.EvaluableCredentialCriteriaRegistry; + +/** + * An abstract implementation of {@link CredentialResolver} which filters the returned Credentials + * based on the instances of {@link EvaluableCredentialCriteria} which are present in the set of + * criteria, or which are obtained via lookup in the {@link EvaluableCredentialCriteriaRegistry}. + */ +public abstract class AbstractCriteriaFilteringCredentialResolver extends AbstractCredentialResolver { + + /** Flag to pass to CriteriaFilteringIterable constructor parameter 'meetAllCriteria'. */ + private boolean meetAllCriteria; + + /** Flag to pass to CriteriaFilteringIterable constructor 'unevaluableSatisfies'. */ + private boolean unevaluableSatisfies; + + /** + * Constructor. + * + */ + public AbstractCriteriaFilteringCredentialResolver() { + super(); + meetAllCriteria = true; + unevaluableSatisfies = true; + } + + /** {@inheritDoc} */ + public Iterable resolve(CriteriaSet criteriaSet) throws SecurityException { + Iterable storeCandidates = resolveFromSource(criteriaSet); + Set> evaluableCriteria = getEvaluableCriteria(criteriaSet); + if (evaluableCriteria.isEmpty()) { + return storeCandidates; + } else { + return new CriteriaFilteringIterable(storeCandidates, evaluableCriteria, + meetAllCriteria, unevaluableSatisfies); + } + } + + /** + * Get whether all {@link EvaluableCredentialCriteria} must be met to return + * a credential, or only one or more evaluable criteria. + * + * See also {@link CriteriaFilteringIterator}. + * + * @return Returns the meetAllCriteria flag. + */ + public boolean isMeetAllCriteria() { + return meetAllCriteria; + } + + /** + * Set whether all {@link EvaluableCredentialCriteria} must be met to return + * a credential, or only one or more evaluable criteria. + * + * See also {@link CriteriaFilteringIterator}. + * + * @param flag the new meetAllCriteria flag value. + */ + public void setMeetAllCriteria(boolean flag) { + meetAllCriteria = flag; + } + + /** + * Get the flag which determines the processing behavior when + * an {@link EvaluableCredentialCriteria} is unable to evaluate + * a Credential. + * + * See also {@link CriteriaFilteringIterator}. + * + * @return Returns the unevaluableSatisfies flag. + */ + public boolean isUnevaluableSatisfies() { + return unevaluableSatisfies; + } + + /** + * Set the flag which determines the processing behavior when + * an {@link EvaluableCredentialCriteria} is unable to evaluate + * a Credential. + * + * See also {@link CriteriaFilteringIterator}. + * + * @param flag the new unevaluableSatisfies flag value. + */ + public void setUnevaluableSatisfies(boolean flag) { + unevaluableSatisfies = flag; + } + + /** + * Subclasses are required to implement this method to resolve credentials from the + * implementation-specific type of underlying credential source. + * + * @param criteriaSet the set of criteria used to resolve credentials from the credential source + * @return an Iterable for the resolved set of credentials + * @throws SecurityException thrown if there is an error resolving credentials from the credential source + */ + protected abstract Iterable resolveFromSource(CriteriaSet criteriaSet) + throws SecurityException; + + /** + * Extract the evaluable credential criteria from the criteria set. + * + * @param criteriaSet the set of credential criteria to process. + * @return a set of evaluable Credential criteria + * @throws SecurityException thrown if there is an error obtaining an instance of EvaluableCredentialCriteria + * from the EvaluableCredentialCriteriaRegistry + */ + private Set> getEvaluableCriteria(CriteriaSet criteriaSet) throws SecurityException { + Set> evaluable = new HashSet>(criteriaSet.size()); + for (Criteria criteria : criteriaSet) { + if (criteria instanceof EvaluableCredentialCriteria) { + evaluable.add((EvaluableCredentialCriteria) criteria); + } else { + EvaluableCredentialCriteria evaluableCriteria = + EvaluableCredentialCriteriaRegistry.getEvaluator(criteria); + if (evaluableCriteria != null) { + evaluable.add(evaluableCriteria); + } + } + } + return evaluable; + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/security/credential/BasicCredential.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/security/credential/BasicCredential.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/security/credential/BasicCredential.java 17 Aug 2012 15:17:17 -0000 1.1 @@ -0,0 +1,103 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.security.credential; + +import java.security.PrivateKey; +import java.security.PublicKey; + +import javax.crypto.SecretKey; + +import org.opensaml.xml.util.DatatypeHelper; +import org.opensaml.xml.util.LazySet; + +/** + * A basic implementation of {@link Credential}. + */ +public class BasicCredential extends AbstractCredential { + + /** Constructor. */ + public BasicCredential() { + super(); + keyNames = new LazySet(); + usageType = UsageType.UNSPECIFIED; + } + + /** {@inheritDoc} */ + public Class getCredentialType() { + return Credential.class; + } + + /** + * Sets the ID of the entity this credential is for. + * + * @param id ID of the entity this credential is for + */ + public void setEntityId(String id) { + entityID = DatatypeHelper.safeTrimOrNullString(id); + } + + /** + * Sets the usage type for this credential. + * + * @param usage usage type for this credential + */ + public void setUsageType(UsageType usage) { + if (usage != null) { + usageType = usage; + } else { + usageType = UsageType.UNSPECIFIED; + } + } + + /** + * Sets the public key for this credential. + * + * @param key public key for this credential + */ + public void setPublicKey(PublicKey key) { + publicKey = key; + if (key != null) { + setSecretKey(null); + } + } + + /** + * Sets the secret key for this credential. + * + * @param key secret key for this credential + */ + public void setSecretKey(SecretKey key) { + secretKey = key; + if (key != null) { + setPublicKey(null); + setPrivateKey(null); + } + } + + /** + * Sets the private key for this credential. + * + * @param key private key for this credential + */ + public void setPrivateKey(PrivateKey key) { + privateKey = key; + if (key != null) { + setSecretKey(null); + } + } +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/security/credential/BasicKeyInfoGeneratorFactory.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/security/credential/BasicKeyInfoGeneratorFactory.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/security/credential/BasicKeyInfoGeneratorFactory.java 17 Aug 2012 15:17:18 -0000 1.1 @@ -0,0 +1,255 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.security.credential; + +import java.util.List; + +import org.opensaml.xml.Configuration; +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.security.SecurityException; +import org.opensaml.xml.security.keyinfo.KeyInfoGenerator; +import org.opensaml.xml.security.keyinfo.KeyInfoGeneratorFactory; +import org.opensaml.xml.security.keyinfo.KeyInfoHelper; +import org.opensaml.xml.signature.KeyInfo; +import org.opensaml.xml.signature.impl.KeyInfoBuilder; +import org.opensaml.xml.util.DatatypeHelper; + + +/** + * A factory implementation which produces instances of {@link KeyInfoGenerator} capable of + * handling the information contained within a {@link Credential}. + * + * All boolean options default to false. + */ +public class BasicKeyInfoGeneratorFactory implements KeyInfoGeneratorFactory { + + /** The set of options configured for the factory. */ + private BasicOptions options; + + /** + * Constructor. + * + * All boolean options are initialzed as false; + */ + public BasicKeyInfoGeneratorFactory() { + options = newOptions(); + } + + /** {@inheritDoc} */ + public Class getCredentialType() { + return Credential.class; + } + + /** {@inheritDoc} */ + public boolean handles(Credential credential) { + // This top-level class can handle any Credential type, with output limited to basic Credential information + return true; + } + + /** {@inheritDoc} */ + public KeyInfoGenerator newInstance() { + //TODO lock options during cloning ? + BasicOptions newOptions = options.clone(); + return new BasicKeyInfoGenerator(newOptions); + } + + /** + * Get the option to emit the entity ID value in a Credential as a KeyName element. + * + * @return return the option value + */ + public boolean emitEntityIDAsKeyName() { + return options.emitEntityIDAsKeyName; + } + + /** + * Set the option to emit the entity ID value in a Credential as a KeyName element. + * + * @param newValue the new option value to set + */ + public void setEmitEntityIDAsKeyName(boolean newValue) { + options.emitEntityIDAsKeyName = newValue; + } + + /** + * Get the option to emit key names found in a Credential as KeyName elements. + * + * @return the option value + */ + public boolean emitKeyNames() { + return options.emitKeyNames; + } + + /** + * Set the option to emit key names found in a Credential as KeyName elements. + * + * @param newValue the new option value to set + */ + public void setEmitKeyNames(boolean newValue) { + options.emitKeyNames = newValue; + } + + /** + * Get the option to emit the value of {@link Credential#getPublicKey()} as a KeyValue element. + * + * @return the option value + */ + public boolean emitPublicKeyValue() { + return options.emitPublicKeyValue; + } + + /** + * Set the option to emit the value of {@link Credential#getPublicKey()} as a KeyValue element. + * + * @param newValue the new option value to set + */ + public void setEmitPublicKeyValue(boolean newValue) { + options.emitPublicKeyValue = newValue; + + } + + /** + * Get a new instance to hold options. Used by the top-level superclass constructor. + * Subclasses MUST override to produce an instance of the appropriate + * subclass of {@link BasicOptions}. + * + * @return a new instance of factory/generator options + */ + protected BasicOptions newOptions() { + return new BasicOptions(); + } + + /** + * Get the options of this instance. Used by subclass constructors to get the options built by + * the top-level class constructor with {@link #newOptions()}. + * + * @return the options instance + */ + protected BasicOptions getOptions() { + return options; + } + + /** + * An implementation of {@link KeyInfoGenerator} capable of handling the information + * contained within a {@link Credential}. + */ + public class BasicKeyInfoGenerator implements KeyInfoGenerator { + + /** The set of options to be used by the generator.*/ + private BasicOptions options; + + /** Builder for KeyInfo objects. */ + private KeyInfoBuilder keyInfoBuilder; + + /** + * Constructor. + * + * @param newOptions the options to be used by the generator + */ + protected BasicKeyInfoGenerator(BasicOptions newOptions) { + options = newOptions; + keyInfoBuilder = + (KeyInfoBuilder) Configuration.getBuilderFactory().getBuilder(KeyInfo.DEFAULT_ELEMENT_NAME); + } + + /** {@inheritDoc} */ + public KeyInfo generate(Credential credential) throws SecurityException { + KeyInfo keyInfo = keyInfoBuilder.buildObject(); + + processKeyNames(keyInfo, credential); + processEntityID(keyInfo, credential); + processPublicKey(keyInfo, credential); + + List children = keyInfo.getOrderedChildren(); + if (children != null && children.size() > 0) { + return keyInfo; + } else { + return null; + } + } + + /** Process the values of {@link Credential#getKeyNames()}. + * + * @param keyInfo the KeyInfo that is being built + * @param credential the Credential that is geing processed + */ + protected void processKeyNames(KeyInfo keyInfo, Credential credential) { + if (options.emitKeyNames) { + for (String keyNameValue : credential.getKeyNames()) { + if ( ! DatatypeHelper.isEmpty(keyNameValue)) { + KeyInfoHelper.addKeyName(keyInfo, keyNameValue); + } + } + } + } + + /** Process the value of {@link Credential#getEntityId()}. + * + * @param keyInfo the KeyInfo that is being built + * @param credential the Credential that is geing processed + */ + protected void processEntityID(KeyInfo keyInfo, Credential credential) { + if (options.emitEntityIDAsKeyName) { + String keyNameValue = credential.getEntityId(); + if ( ! DatatypeHelper.isEmpty(keyNameValue)) { + KeyInfoHelper.addKeyName(keyInfo, keyNameValue); + } + } + } + + /** Process the value of {@link Credential#getPublicKey()}. + * + * @param keyInfo the KeyInfo that is being built + * @param credential the Credential that is geing processed + */ + protected void processPublicKey(KeyInfo keyInfo, Credential credential) { + if (options.emitPublicKeyValue) { + if (credential.getPublicKey() != null) { + KeyInfoHelper.addPublicKey(keyInfo, credential.getPublicKey()); + } + } + } + } + + /** + * Options to be used in the production of a {@link KeyInfo} from a {@link Credential}. + */ + protected class BasicOptions implements Cloneable { + + /** Emit key names found in a Credential as KeyName elements. */ + private boolean emitKeyNames; + + /** Emit the entity ID value in a Credential as a KeyName element. */ + private boolean emitEntityIDAsKeyName; + + /** Emit the value of {@link Credential#getPublicKey()} as a KeyValue element. */ + private boolean emitPublicKeyValue; + + /** {@inheritDoc} */ + protected BasicOptions clone() { + try { + return (BasicOptions) super.clone(); + } catch (CloneNotSupportedException e) { + // we know we're cloneable, so this will never happen + return null; + } + } + + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/security/credential/ChainingCredentialResolver.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/security/credential/ChainingCredentialResolver.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/security/credential/ChainingCredentialResolver.java 17 Aug 2012 15:17:18 -0000 1.1 @@ -0,0 +1,220 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.security.credential; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.NoSuchElementException; + +import org.opensaml.xml.security.CriteriaSet; +import org.opensaml.xml.security.SecurityException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * An implementation of {@link CredentialResolver} which chains together one or more underlying credential resolver + * implementations. Resolved credentials are returned from all underlying resolvers in the chain, in the order implied + * by the order of the resolvers in the chain. + */ +public class ChainingCredentialResolver extends AbstractCredentialResolver { + + /** Logger. */ + private final Logger log = LoggerFactory.getLogger(ChainingCredentialResolver.class); + + /** List of credential resolvers in the chain. */ + private List resolvers; + + /** + * Constructor. + */ + public ChainingCredentialResolver() { + resolvers = new ArrayList(); + } + + /** + * Get the (modifiable) list of credential resolvers which comprise the resolver chain. + * + * @return the list of credential resolvers in the chain + */ + public List getResolverChain() { + return resolvers; + } + + /** {@inheritDoc} */ + public Iterable resolve(CriteriaSet criteriaSet) throws SecurityException { + if (resolvers.isEmpty()) { + log.warn("Chaining credential resolver resolution was attempted with an empty resolver chain"); + throw new IllegalStateException("The resolver chain is empty"); + } + return new CredentialIterable(this, criteriaSet); + } + + /** + * Implementation of {@link Iterable} to be returned by {@link ChainingCredentialResolver}. + */ + public class CredentialIterable implements Iterable { + + /** The chaining credential resolver which owns this instance. */ + private ChainingCredentialResolver parent; + + /** The criteria set on which to base resolution. */ + private CriteriaSet critSet; + + /** + * Constructor. + * + * @param resolver the chaining parent of this iterable + * @param criteriaSet the set of criteria which is input to the underyling resolvers + */ + public CredentialIterable(ChainingCredentialResolver resolver, CriteriaSet criteriaSet) { + parent = resolver; + critSet = criteriaSet; + } + + /** {@inheritDoc} */ + public Iterator iterator() { + return new CredentialIterator(parent, critSet); + } + + } + + /** + * Implementation of {@link Iterator} to be returned (indirectly) by {@link ChainingCredentialResolver}. + */ + public class CredentialIterator implements Iterator { + + /** Logger. */ + private final Logger log = LoggerFactory.getLogger(CredentialIterator.class); + + /** The chaining credential resolver which owns this instance. */ + private ChainingCredentialResolver parent; + + /** The criteria set on which to base resolution. */ + private CriteriaSet critSet; + + /** The iterator over resolvers in the chain. */ + private Iterator resolverIterator; + + /** The iterator over Credential instances from the current resolver. */ + private Iterator credentialIterator; + + /** The current resolver which is returning credentials. */ + private CredentialResolver currentResolver; + + /** The next credential that is safe to return. */ + private Credential nextCredential; + + /** + * Constructor. + * + * @param resolver the chaining parent of this iterable + * @param criteriaSet the set of criteria which is input to the underyling resolvers + */ + public CredentialIterator(ChainingCredentialResolver resolver, CriteriaSet criteriaSet) { + parent = resolver; + critSet = criteriaSet; + resolverIterator = parent.getResolverChain().iterator(); + credentialIterator = getNextCredentialIterator(); + nextCredential = null; + } + + /** {@inheritDoc} */ + public boolean hasNext() { + if (nextCredential != null) { + return true; + } + nextCredential = getNextCredential(); + if (nextCredential != null) { + return true; + } + return false; + } + + /** {@inheritDoc} */ + public Credential next() { + Credential tempCred; + if (nextCredential != null) { + tempCred = nextCredential; + nextCredential = null; + return tempCred; + } + tempCred = getNextCredential(); + if (tempCred != null) { + return tempCred; + } else { + throw new NoSuchElementException("No more Credential elements are available"); + } + } + + /** {@inheritDoc} */ + public void remove() { + throw new UnsupportedOperationException("Remove operation is not supported by this iterator"); + } + + /** + * Get the iterator from the next resolver in the chain. + * + * @return an iterator of credentials + */ + private Iterator getNextCredentialIterator() { + while (resolverIterator.hasNext()) { + currentResolver = resolverIterator.next(); + log.debug("Getting credential iterator from next resolver in chain: {}", currentResolver.getClass().toString()); + try { + return currentResolver.resolve(critSet).iterator(); + } catch (SecurityException e) { + log.error(String.format("Error resolving credentials from chaining resolver member '%s'", + currentResolver.getClass().getName()), e); + if (resolverIterator.hasNext()) { + log.error("Will attempt to resolve credentials from next member of resolver chain"); + } + } + } + + log.debug("No more credential resolvers available in the resolver chain"); + currentResolver = null; + return null; + } + + /** + * Get the next credential that will be returned by this iterator. + * + * @return the next credential to return + */ + private Credential getNextCredential() { + if (credentialIterator != null) { + if (credentialIterator.hasNext()) { + return credentialIterator.next(); + } + } + + credentialIterator = getNextCredentialIterator(); + while (credentialIterator != null) { + if (credentialIterator.hasNext()) { + return credentialIterator.next(); + } + credentialIterator = getNextCredentialIterator(); + } + + return null; + } + + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/security/credential/CollectionCredentialResolver.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/security/credential/CollectionCredentialResolver.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/security/credential/CollectionCredentialResolver.java 17 Aug 2012 15:17:17 -0000 1.1 @@ -0,0 +1,78 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.security.credential; + +import java.util.ArrayList; +import java.util.Collection; + +import org.opensaml.xml.security.CriteriaSet; +import org.opensaml.xml.security.SecurityException; +import org.opensaml.xml.security.credential.criteria.EvaluableCredentialCriteria; +import org.opensaml.xml.security.credential.criteria.EvaluableCredentialCriteriaRegistry; + +/** + * An implementation of {@link CredentialResolver} which uses a {@link Collection} as the + * underlying credential source. + * + *

+ * The credentials returned are filtered based on any + * {@link EvaluableCredentialCriteria} which may have been present in the specified criteria set, or + * which are resolved by lookup in the {@link EvaluableCredentialCriteriaRegistry}. + *

+ */ +public class CollectionCredentialResolver extends AbstractCriteriaFilteringCredentialResolver { + + /** The collection of credentials which is the underlying store for the resolver. */ + private Collection collection; + + /** + * Constructor. + * + * An {@link ArrayList} is used as the underlying collection implementation. + * + */ + public CollectionCredentialResolver() { + super(); + collection = new ArrayList(); + } + + /** + * Constructor. + * + * @param credentials the credential collection which is the backing store for the resolver + */ + public CollectionCredentialResolver(Collection credentials) { + super(); + collection = credentials; + } + + /** + * Get the (modifiable) credential collection which is the backing store for the resolver. + * + * @return the credential collection backing store + */ + public Collection getCollection() { + return collection; + } + + /** {@inheritDoc} */ + protected Iterable resolveFromSource(CriteriaSet criteriaSet) throws SecurityException { + return collection; + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/security/credential/Credential.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/security/credential/Credential.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/security/credential/Credential.java 17 Aug 2012 15:17:18 -0000 1.1 @@ -0,0 +1,94 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.security.credential; + +import java.security.PrivateKey; +import java.security.PublicKey; +import java.util.Collection; + +import javax.crypto.SecretKey; + +/** + * A credential for an entity. A particular credential may contain either asymmetric key information (a public key + * and optionally the corresponding private key), or a symmetric (secret) key, but never both. + * With asymmetric key-based credentials, local entity credentials will usually contain both a public + * and private key while peer credentails will normally contain only a public key. + */ +public interface Credential { + + /** + * The unique ID of the entity this credential is for. + * + * @return unique ID of the entity this credential is for + */ + public String getEntityId(); + + /** + * Gets usage type of this credential. + * + * @return usage type of this credential + */ + public UsageType getUsageType(); + + /** + * Gets key names for this credential. These names may be used to reference a key(s) exchanged + * through an out-of-band aggreement. Implementations may or may not implement means to resolve + * these names into keys retrievable through the {@link #getPublicKey()}, {@link #getPrivateKey()} + * or {@link #getSecretKey()} methods. + * + * @return key names for this credential + */ + public Collection getKeyNames(); + + /** + * Gets the public key for the entity. + * + * @return public key for the entity + */ + public PublicKey getPublicKey(); + + /** + * Gets the private key for the entity if there is one. + * + * @return the private key for the entity + */ + public PrivateKey getPrivateKey(); + + /** + * Gets the secret key for this entity. + * + * @return secret key for this entity + */ + public SecretKey getSecretKey(); + + /** + * Get the set of credential context information, which provides additional information + * specific to the contexts in which the credential was resolved. + * + * @return set of resolution contexts of the credential + */ + public CredentialContextSet getCredentalContextSet(); + + /** + * Get the primary type of the credential instance. This will usually be the primary sub-interface + * of {@link Credential} implemented by an implementation. + * + * @return the credential type + */ + public Class getCredentialType(); +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/security/credential/CredentialContext.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/security/credential/CredentialContext.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/security/credential/CredentialContext.java 17 Aug 2012 15:17:17 -0000 1.1 @@ -0,0 +1,26 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.security.credential; + +/** + * Marker interface for implementations which hold information specific to a a particular context within + * which a {@link CredentialResolver} resolves a {@link Credential}. + */ +public interface CredentialContext { + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/security/credential/CredentialContextSet.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/security/credential/CredentialContextSet.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/security/credential/CredentialContextSet.java 17 Aug 2012 15:17:18 -0000 1.1 @@ -0,0 +1,30 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.security.credential; + +import org.opensaml.xml.util.ClassIndexedSet; + + +/** + * This class holds instances of {@link CredentialContext} which represent information + * about the context in which a {@link CredentialResolver} has resolved a {@link Credential}. + */ +public class CredentialContextSet extends ClassIndexedSet { + + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/security/credential/CredentialResolver.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/security/credential/CredentialResolver.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/security/credential/CredentialResolver.java 17 Aug 2012 15:17:18 -0000 1.1 @@ -0,0 +1,30 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.security.credential; + + +import org.opensaml.xml.security.Criteria; +import org.opensaml.xml.security.CriteriaSet; +import org.opensaml.xml.security.Resolver; + +/** + * A resolver which uses {@link Criteria} to resolve and return instances of {@link Credential}. + */ +public interface CredentialResolver extends Resolver{ + +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/security/credential/FilesystemCredentialResolver.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/security/credential/FilesystemCredentialResolver.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/security/credential/FilesystemCredentialResolver.java 17 Aug 2012 15:17:18 -0000 1.1 @@ -0,0 +1,59 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.security.credential; + +import java.util.Map; + +import org.opensaml.xml.security.CriteriaSet; + +//TODO amend docs (and impl) for symmetric key storage and retrieval + + +/** + * NOTE: this class is not yet implemented + * A {@link CredentialResolver} that pulls credential information from the file system. + * + * This credential resolver attempts to retrieve credential information from the file system. Specifically it will + * attempt to find key, cert, and crl information from files within the given directory. The filename must start with + * the entity ID and be followed by one of the follow extensions: + * + *
    + *
  • .name - for key names. File must contain a carriage return seperated list of key names
  • + *
  • .priv - for private key. File must contain one PEM or DER encoded private key
  • + *
  • .pub - for public keys. File must contain one or more PEM or DER encoded private key
  • + *
  • .crt - for public certificates. File must contain one or more PEM or DER encoded X.509 certificates
  • + *
  • .crl - for certificate revocation lists. File must contain one or more CRLs
  • + *
+ */ +public class FilesystemCredentialResolver extends AbstractCriteriaFilteringCredentialResolver { + + /** + * Constructor. + * + * @param credentialDirectory directory credential information can be found in + * @param passwords passwords for encrypted private keys, key is the entity ID, value is the password + */ + public FilesystemCredentialResolver(String credentialDirectory, Map passwords) { + super(); + } + + /** {@inheritDoc} */ + protected Iterable resolveFromSource(CriteriaSet criteriaSet) { + throw new UnsupportedOperationException("Functionality not yet implemented"); + } +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/security/credential/KeyStoreCredentialResolver.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/security/credential/KeyStoreCredentialResolver.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/security/credential/KeyStoreCredentialResolver.java 17 Aug 2012 15:17:17 -0000 1.1 @@ -0,0 +1,279 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.security.credential; + +import java.security.GeneralSecurityException; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.UnrecoverableEntryException; +import java.security.KeyStore.SecretKeyEntry; +import java.security.cert.X509Certificate; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Map; + +import org.opensaml.xml.security.CriteriaSet; +import org.opensaml.xml.security.SecurityException; +import org.opensaml.xml.security.criteria.EntityIDCriteria; +import org.opensaml.xml.security.criteria.UsageCriteria; +import org.opensaml.xml.security.x509.BasicX509Credential; +import org.opensaml.xml.security.x509.X509Credential; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * A {@link CredentialResolver} that extracts {@link Credential}'s from a key store. + * + * If no key usage type is presented at construction time this resolver will return the key, if available, regardless of + * the usage type provided to its resolve method. + */ +public class KeyStoreCredentialResolver extends AbstractCriteriaFilteringCredentialResolver { + + /** Class logger. */ + private final Logger log = LoggerFactory.getLogger(KeyStoreCredentialResolver.class); + + /** Key store credentials are retrieved from. */ + private KeyStore keyStore; + + /** Passwords for keys. The key must be the entity ID, the value the password. */ + private Map keyPasswords; + + /** Usage type of all keys in the store. */ + private UsageType keystoreUsage; + + /** + * Constructor. + * + * @param store key store credentials are retrieved from + * @param passwords for key entries, map key is the entity id, map value is the password + * + * @throws IllegalArgumentException thrown if the given keystore is null + */ + public KeyStoreCredentialResolver(KeyStore store, Map passwords) throws IllegalArgumentException { + this(store, passwords, null); + } + + /** + * Constructor. + * + * @param store key store credentials are retrieved from + * @param passwords for key entries, map key is the entity id, map value is the password + * @param usage usage type of all keys in the store + * + * @throws IllegalArgumentException thrown if the given keystore is null + */ + public KeyStoreCredentialResolver(KeyStore store, Map passwords, UsageType usage) + throws IllegalArgumentException { + super(); + + if (store == null) { + throw new IllegalArgumentException("Provided key store may not be null."); + } + + try { + store.size(); + } catch (KeyStoreException e) { + throw new IllegalArgumentException("Keystore has not been initialized."); + } + + keyStore = store; + + if (usage != null) { + keystoreUsage = usage; + } else { + keystoreUsage = UsageType.UNSPECIFIED; + } + + keyPasswords = passwords; + } + + /** {@inheritDoc} */ + protected Iterable resolveFromSource(CriteriaSet criteriaSet) throws SecurityException { + + checkCriteriaRequirements(criteriaSet); + + String entityID = criteriaSet.get(EntityIDCriteria.class).getEntityID(); + UsageCriteria usageCriteria = criteriaSet.get(UsageCriteria.class); + UsageType usage; + if (usageCriteria != null) { + usage = usageCriteria.getUsage(); + } else { + usage = UsageType.UNSPECIFIED; + } + if (!matchUsage(keystoreUsage, usage)) { + log.debug("Specified usage criteria {} does not match keystore usage {}", usage, keystoreUsage); + log.debug("Can not resolve credentials from this keystore"); + return Collections.emptySet(); + } + + KeyStore.PasswordProtection keyPassword = null; + if (keyPasswords.containsKey(entityID)) { + keyPassword = new KeyStore.PasswordProtection(keyPasswords.get(entityID).toCharArray()); + } + + KeyStore.Entry keyStoreEntry = null; + try { + keyStoreEntry = keyStore.getEntry(entityID, keyPassword); + } catch (UnrecoverableEntryException e) { + log.error("Unable to retrieve keystore entry for entityID (keystore alias): " + entityID); + log.error("Check for invalid keystore entityID/alias entry password"); + throw new SecurityException("Could not retrieve entry from keystore", e); + } catch (GeneralSecurityException e) { + log.error("Unable to retrieve keystore entry for entityID (keystore alias): " + entityID, e); + throw new SecurityException("Could not retrieve entry from keystore", e); + } + + if (keyStoreEntry == null) { + log.debug("Keystore entry for entity ID (keystore alias) {} does not exist", entityID); + return Collections.emptySet(); + } + + Credential credential = buildCredential(keyStoreEntry, entityID, keystoreUsage); + return Collections.singleton(credential); + } + + /** + * Check that required credential criteria are available. + * + * @param criteriaSet the credential criteria set to evaluate + */ + protected void checkCriteriaRequirements(CriteriaSet criteriaSet) { + EntityIDCriteria entityCriteria = criteriaSet.get(EntityIDCriteria.class); + if (entityCriteria == null) { + log.error("EntityIDCriteria was not specified in the criteria set, resolution can not be attempted"); + throw new IllegalArgumentException("No EntityIDCriteria was available in criteria set"); + } + } + + /** + * Match usage enum type values from keystore configured usage and from credential criteria. + * + * @param keyStoreUsage the usage type configured for the keystore + * @param criteriaUsage the value from credential criteria + * @return true if the two usage specifiers match for purposes of resolving credentials, false otherwise + */ + protected boolean matchUsage(UsageType keyStoreUsage, UsageType criteriaUsage) { + if (keyStoreUsage == UsageType.UNSPECIFIED || criteriaUsage == UsageType.UNSPECIFIED) { + return true; + } + return keyStoreUsage == criteriaUsage; + } + + /** + * Build a credential instance from the key store entry. + * + * @param keyStoreEntry the key store entry to process + * @param entityID the entityID to include in the credential + * @param usage the usage type to include in the credential + * @return the new credential instance, appropriate to the type of key store entry being processed + * @throws SecurityException throw if there is a problem building a credential from the key store entry + */ + protected Credential buildCredential(KeyStore.Entry keyStoreEntry, String entityID, UsageType usage) + throws SecurityException { + + log.debug("Building credential from keystore entry for entityID {}, usage type {}", entityID, usage); + + Credential credential = null; + if (keyStoreEntry instanceof KeyStore.PrivateKeyEntry) { + credential = processPrivateKeyEntry((KeyStore.PrivateKeyEntry) keyStoreEntry, entityID, keystoreUsage); + } else if (keyStoreEntry instanceof KeyStore.TrustedCertificateEntry) { + credential = processTrustedCertificateEntry((KeyStore.TrustedCertificateEntry) keyStoreEntry, entityID, + keystoreUsage); + } else if (keyStoreEntry instanceof KeyStore.SecretKeyEntry) { + credential = processSecretKeyEntry((KeyStore.SecretKeyEntry) keyStoreEntry, entityID, keystoreUsage); + } else { + throw new SecurityException("KeyStore entry was of an unsupported type: " + + keyStoreEntry.getClass().getName()); + } + return credential; + } + + /** + * Build an X509Credential from a keystore trusted certificate entry. + * + * @param trustedCertEntry the entry being processed + * @param entityID the entityID to set + * @param usage the usage type to set + * @return new X509Credential instance + */ + protected X509Credential processTrustedCertificateEntry(KeyStore.TrustedCertificateEntry trustedCertEntry, + String entityID, UsageType usage) { + + log.debug("Processing TrustedCertificateEntry from keystore"); + + BasicX509Credential credential = new BasicX509Credential(); + credential.setEntityId(entityID); + credential.setUsageType(usage); + + X509Certificate cert = (X509Certificate) trustedCertEntry.getTrustedCertificate(); + + credential.setEntityCertificate(cert); + + ArrayList certChain = new ArrayList(); + certChain.add(cert); + credential.setEntityCertificateChain(certChain); + + return credential; + } + + /** + * Build an X509Credential from a keystore private key entry. + * + * @param privateKeyEntry the entry being processed + * @param entityID the entityID to set + * @param usage the usage type to set + * @return new X509Credential instance + */ + protected X509Credential processPrivateKeyEntry(KeyStore.PrivateKeyEntry privateKeyEntry, String entityID, + UsageType usage) { + + log.debug("Processing PrivateKeyEntry from keystore"); + + BasicX509Credential credential = new BasicX509Credential(); + credential.setEntityId(entityID); + credential.setUsageType(usage); + + credential.setPrivateKey(privateKeyEntry.getPrivateKey()); + + credential.setEntityCertificate((X509Certificate) privateKeyEntry.getCertificate()); + credential.setEntityCertificateChain(Arrays.asList((X509Certificate[]) privateKeyEntry.getCertificateChain())); + + return credential; + } + + /** + * Build a Credential from a keystore secret key entry. + * + * @param secretKeyEntry the entry being processed + * @param entityID the entityID to set + * @param usage the usage type to set + * @return new Credential instance + */ + protected Credential processSecretKeyEntry(SecretKeyEntry secretKeyEntry, String entityID, UsageType usage) { + log.debug("Processing SecretKeyEntry from keystore"); + + BasicCredential credential = new BasicCredential(); + credential.setEntityId(entityID); + credential.setUsageType(usage); + + credential.setSecretKey(secretKeyEntry.getSecretKey()); + + return credential; + } +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/security/credential/StaticCredentialResolver.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/security/credential/StaticCredentialResolver.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/security/credential/StaticCredentialResolver.java 17 Aug 2012 15:17:18 -0000 1.1 @@ -0,0 +1,65 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.security.credential; + +import java.util.ArrayList; +import java.util.List; + +import org.opensaml.xml.security.CriteriaSet; +import org.opensaml.xml.security.SecurityException; + +/** + * Simple implementation of {@link CredentialResolver} which just stores and returns a static set of credentials. + * + *

+ * Note: no filtering or other evaluation of the credentials is performed. Any Criteria + * specified are ignored. For a similar Collection-based CredentialResolver implementation which does support + * evaluation and filtering based on supplied evaluable criteria, see {@link CollectionCredentialResolver}. + *

+ */ +public class StaticCredentialResolver extends AbstractCredentialResolver { + + /** List of credentials held by this resolver. */ + private List creds; + + /** + * Constructor. + * + * @param credentials collection of credentials to be held by this resolver + */ + public StaticCredentialResolver(List credentials) { + creds = new ArrayList(); + creds.addAll(credentials); + } + + /** + * Constructor. + * + * @param credential a single credential to be held by this resolver + */ + public StaticCredentialResolver(Credential credential) { + creds = new ArrayList(); + creds.add(credential); + } + + /** {@inheritDoc} */ + public Iterable resolve(CriteriaSet criteria) throws SecurityException { + return creds; + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/security/credential/UsageType.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/security/credential/UsageType.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/security/credential/UsageType.java 17 Aug 2012 15:17:17 -0000 1.1 @@ -0,0 +1,31 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.security.credential; + +/** Credential usage types. */ +public enum UsageType { + + /** Key used for encryption processes. */ + ENCRYPTION, + + /** Key used for signature processes including TLS/SSL. */ + SIGNING, + + /** Denotes that the purpose of the key was not specified. */ + UNSPECIFIED +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/security/credential/package.html =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/security/credential/package.html,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/security/credential/package.html 17 Aug 2012 15:17:17 -0000 1.1 @@ -0,0 +1,30 @@ + + +Interfaces and classes related to credentials and ways to represent +them. + +Developers will generally create and populate CredentialResolvers +during application initialization time. CredentialCriteria can then be +constructured to model the information the application has about a +particular credential and then provided to the CredentialResolver in +order retrieve the previously loaded credential information. Here are a +couple of use cases where this approach might be used: +
    +
  • An application wishes to decrypt a message from one of many + peers. The encrypted message contains a KeyInfo which itself contains + the public key used to encrypt the data. The application can then use + the public key to lookup its appropriate private key and decrypt the + message.
  • +
  • An application uses client-cert authentication via TLS when + communicating with a peer. Upon receipt of the peers certificate the + application uses the provide entity certificate to lookup additional + information associated with this credential, including CRLs, to + determine if the credential should be trusted. It then looks up it's + credential for the given peer and uses it to authenticate. Once + completed the application stores the TLS session key in a + CredentialResolver so that it may be used during encryption processes. +
  • +
+ + + \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/security/credential/criteria/EvaluableCredentialCriteria.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/security/credential/criteria/EvaluableCredentialCriteria.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/security/credential/criteria/EvaluableCredentialCriteria.java 17 Aug 2012 15:17:16 -0000 1.1 @@ -0,0 +1,28 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.security.credential.criteria; + +import org.opensaml.xml.security.EvaluableCriteria; +import org.opensaml.xml.security.credential.Credential; + +/** + * Marker interface for evaluable credential resolver criteria. + */ +public interface EvaluableCredentialCriteria extends EvaluableCriteria { + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/security/credential/criteria/EvaluableCredentialCriteriaRegistry.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/security/credential/criteria/EvaluableCredentialCriteriaRegistry.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/security/credential/criteria/EvaluableCredentialCriteriaRegistry.java 17 Aug 2012 15:17:16 -0000 1.1 @@ -0,0 +1,261 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.security.credential.criteria; + +import java.io.IOException; +import java.io.InputStream; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; + +import org.opensaml.xml.Configuration; +import org.opensaml.xml.security.Criteria; +import org.opensaml.xml.security.SecurityException; +import org.opensaml.xml.security.credential.Credential; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * A registry which manages mappings from types of {@link Criteria} to the class type which can evaluate that criteria's + * data against a {@link Credential} target. That latter class will be a subtype of {@link EvaluableCredentialCriteria}. + * Each EvaluableCredentialCriteria implementation that is registered MUST implement a single-arg + * constructor which takes an instance of the Criteria to be evaluated. The evaluable instance is instantiated + * reflectively based on this requirement. + */ +public final class EvaluableCredentialCriteriaRegistry { + + /** + * Properties file storing default mappings from criteria to evaluable credential criteria. Will be loaded as a + * resource stream relative to this class. + */ + public static final String DEFAULT_MAPPINGS_FILE = "/credential-criteria-registry.properties"; + + /** Storage for the registry mappings. */ + private static Map, Class> registry; + + /** Flag to track whether registry is initialized. */ + private static boolean initialized; + + /** Constructor. */ + private EvaluableCredentialCriteriaRegistry() { + } + + /** + * Get an instance of EvaluableCredentialCriteria which can evaluate the supplied criteria's requirements against a + * Credential target. + * + * @param criteria the criteria to be evaluated against a credential + * @return an instance of of EvaluableCredentialCriteria representing the specified criteria's requirements + * @throws SecurityException thrown if there is an error reflectively instantiating a new instance of + * EvaluableCredentialCriteria based on class information stored in the registry + */ + public static EvaluableCredentialCriteria getEvaluator(Criteria criteria) throws SecurityException { + Logger log = getLogger(); + Class clazz = lookup(criteria.getClass()); + + if (clazz != null) { + log.debug("Registry located evaluable criteria class {} for criteria class {}", clazz.getName(), criteria + .getClass().getName()); + + try { + + Constructor constructor = clazz + .getConstructor(new Class[] { criteria.getClass() }); + + return constructor.newInstance(new Object[] { criteria }); + + } catch (java.lang.SecurityException e) { + log.error("Error instantiating new EvaluableCredentialCriteria instance", e); + throw new SecurityException("Could not create new EvaluableCredentialCriteria", e); + } catch (NoSuchMethodException e) { + log.error("Error instantiating new EvaluableCredentialCriteria instance", e); + throw new SecurityException("Could not create new EvaluableCredentialCriteria", e); + } catch (IllegalArgumentException e) { + log.error("Error instantiating new EvaluableCredentialCriteria instance", e); + throw new SecurityException("Could not create new EvaluableCredentialCriteria", e); + } catch (InstantiationException e) { + log.error("Error instantiating new EvaluableCredentialCriteria instance", e); + throw new SecurityException("Could not create new EvaluableCredentialCriteria", e); + } catch (IllegalAccessException e) { + log.error("Error instantiating new EvaluableCredentialCriteria instance", e); + throw new SecurityException("Could not create new EvaluableCredentialCriteria", e); + } catch (InvocationTargetException e) { + log.error("Error instantiating new EvaluableCredentialCriteria instance", e); + throw new SecurityException("Could not create new EvaluableCredentialCriteria", e); + } + + } else { + log.debug("Registry could not locate evaluable criteria for criteria class {}", criteria.getClass() + .getName()); + } + return null; + } + + /** + * Lookup the class subtype of EvaluableCredentialCriteria which is registered for the specified Criteria class. + * + * @param clazz the Criteria class subtype to lookup + * @return the registered EvaluableCredentialCriteria class subtype + */ + public static synchronized Class lookup(Class clazz) { + return registry.get(clazz); + } + + /** + * Register a credential evaluator class for a criteria class. + * + * @param criteriaClass class subtype of {@link Criteria} + * @param evaluableClass class subtype of {@link EvaluableCredentialCriteria} + */ + public static synchronized void register(Class criteriaClass, + Class evaluableClass) { + Logger log = getLogger(); + + log.debug("Registering class {} as evaluator for class {}", evaluableClass.getName(), criteriaClass.getName()); + + registry.put(criteriaClass, evaluableClass); + + } + + /** + * Deregister a criteria-evaluator mapping. + * + * @param criteriaClass class subtype of {@link Criteria} + */ + public static synchronized void deregister(Class criteriaClass) { + Logger log = getLogger(); + + log.debug("Deregistering evaluator for class {}", criteriaClass.getName()); + registry.remove(criteriaClass); + } + + /** + * Clear all mappings from the registry. + */ + public static synchronized void clearRegistry() { + Logger log = getLogger(); + log.debug("Clearing evaluable criteria registry"); + + registry.clear(); + } + + /** + * Check whether the registry has been initialized. + * + * @return true if registry is already initialized, false otherwise + */ + public static synchronized boolean isInitialized() { + return initialized; + } + + /** + * Initialize the registry. + */ + public static synchronized void init() { + if (isInitialized()) { + return; + } + + registry = new HashMap, Class>(); + + loadDefaultMappings(); + + initialized = true; + } + + /** + * Load the default set of criteria-evaluator mappings from the default mappings properties file. + */ + public static synchronized void loadDefaultMappings() { + Logger log = getLogger(); + log.debug("Loading default evaluable credential criteria mappings"); + InputStream inStream = EvaluableCredentialCriteriaRegistry.class.getResourceAsStream(DEFAULT_MAPPINGS_FILE); + if (inStream == null) { + log.error(String.format("Could not open resource stream from default mappings file '%s'", + DEFAULT_MAPPINGS_FILE)); + return; + } + + Properties defaultMappings = new Properties(); + try { + defaultMappings.load(inStream); + } catch (IOException e) { + log.error("Error loading properties file from resource stream", e); + return; + } + + loadMappings(defaultMappings); + } + + /** + * Load a set of criteria-evaluator mappings from the supplied properties set. + * + * @param mappings properies set where the key is the criteria class name, the value is the evaluator class name + */ + @SuppressWarnings("unchecked") + public static synchronized void loadMappings(Properties mappings) { + Logger log = getLogger(); + for (Object key : mappings.keySet()) { + if (!(key instanceof String)) { + log.error(String.format("Properties key was not an instance of String, was '%s', skipping...", key + .getClass().getName())); + continue; + } + String criteriaName = (String) key; + String evaluatorName = mappings.getProperty(criteriaName); + + ClassLoader classLoader = Configuration.class.getClassLoader(); + Class criteriaClass = null; + try { + criteriaClass = classLoader.loadClass(criteriaName); + } catch (ClassNotFoundException e) { + log.error( + String.format("Could not find criteria class name '%s', skipping registration", criteriaName), + e); + return; + } + + Class evaluableClass = null; + try { + evaluableClass = classLoader.loadClass(evaluatorName); + } catch (ClassNotFoundException e) { + log.error(String + .format("Could not find evaluator class name '%s', skipping registration", criteriaName), e); + return; + } + + register(criteriaClass, evaluableClass); + } + + } + + /** + * Get an SLF4J Logger. + * + * @return a Logger instance + */ + private static Logger getLogger() { + return LoggerFactory.getLogger(EvaluableCredentialCriteriaRegistry.class); + } + + static { + init(); + } +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/security/credential/criteria/EvaluableEntityIDCredentialCriteria.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/security/credential/criteria/EvaluableEntityIDCredentialCriteria.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/security/credential/criteria/EvaluableEntityIDCredentialCriteria.java 17 Aug 2012 15:17:16 -0000 1.1 @@ -0,0 +1,75 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.security.credential.criteria; + +import org.opensaml.xml.security.credential.Credential; +import org.opensaml.xml.security.criteria.EntityIDCriteria; +import org.opensaml.xml.util.DatatypeHelper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Instance of evaluable credential criteria for evaluating a credential's entity ID. + */ +public class EvaluableEntityIDCredentialCriteria implements EvaluableCredentialCriteria { + + /** Logger. */ + private final Logger log = LoggerFactory.getLogger(EvaluableEntityIDCredentialCriteria.class); + + /** Base criteria. */ + private String entityID; + + /** + * Constructor. + * + * @param criteria the criteria which is the basis for evaluation + */ + public EvaluableEntityIDCredentialCriteria(EntityIDCriteria criteria) { + if (criteria == null) { + throw new NullPointerException("Criteria instance may not be null"); + } + entityID = criteria.getEntityID(); + } + + /** + * Constructor. + * + * @param newEntityID the criteria value which is the basis for evaluation + */ + public EvaluableEntityIDCredentialCriteria(String newEntityID) { + if (DatatypeHelper.isEmpty(newEntityID)) { + throw new IllegalArgumentException("Entity ID may not be null"); + } + entityID = newEntityID; + } + + /** {@inheritDoc} */ + public Boolean evaluate(Credential target) { + if (target == null) { + log.error("Credential target was null"); + return null; + } + if (DatatypeHelper.isEmpty(target.getEntityId())) { + log.info("Could not evaluate criteria, credential contained no entity ID"); + return null; + } + Boolean result = entityID.equals(target.getEntityId()); + return result; + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/security/credential/criteria/EvaluableKeyAlgorithmCredentialCriteria.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/security/credential/criteria/EvaluableKeyAlgorithmCredentialCriteria.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/security/credential/criteria/EvaluableKeyAlgorithmCredentialCriteria.java 17 Aug 2012 15:17:16 -0000 1.1 @@ -0,0 +1,104 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.security.credential.criteria; + +import java.security.Key; + +import org.opensaml.xml.security.credential.Credential; +import org.opensaml.xml.security.criteria.KeyAlgorithmCriteria; +import org.opensaml.xml.util.DatatypeHelper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Instance of evaluable credential criteria for evaluating the credential key algorithm. + */ +public class EvaluableKeyAlgorithmCredentialCriteria implements EvaluableCredentialCriteria { + + /** Logger. */ + private final Logger log = LoggerFactory.getLogger(EvaluableKeyAlgorithmCredentialCriteria.class); + + /** Base criteria. */ + private String keyAlgorithm; + + /** + * Constructor. + * + * @param criteria the criteria which is the basis for evaluation + */ + public EvaluableKeyAlgorithmCredentialCriteria(KeyAlgorithmCriteria criteria) { + if (criteria == null) { + throw new NullPointerException("Criteria instance may not be null"); + } + keyAlgorithm = criteria.getKeyAlgorithm(); + } + + /** + * Constructor. + * + * @param newKeyAlgorithm the criteria value which is the basis for evaluation + */ + public EvaluableKeyAlgorithmCredentialCriteria(String newKeyAlgorithm) { + if (DatatypeHelper.isEmpty(newKeyAlgorithm)) { + throw new IllegalArgumentException("Key algorithm may not be null"); + } + keyAlgorithm = newKeyAlgorithm; + } + + /** {@inheritDoc} */ + public Boolean evaluate(Credential target) { + if (target == null) { + log.error("Credential target was null"); + return null; + } + Key key = getKey(target); + if (key == null) { + log.info("Could not evaluate criteria, credential contained no key"); + return null; + } + String algorithm = DatatypeHelper.safeTrimOrNullString(key.getAlgorithm()); + if (algorithm == null) { + log.info("Could not evaluate criteria, key does not specify an algorithm via getAlgorithm()"); + return null; + } + + Boolean result = keyAlgorithm.equals(algorithm); + return result; + } + + /** + * Get the key contained within the credential. + * + * @param credential the credential containing a key + * @return the key from the credential + */ + private Key getKey(Credential credential) { + if (credential.getPublicKey() != null) { + return credential.getPublicKey(); + } else if (credential.getSecretKey() != null) { + return credential.getSecretKey(); + } else if (credential.getPrivateKey() != null) { + // There should have been a corresponding public key, but just in case... + return credential.getPrivateKey(); + } else { + return null; + } + + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/security/credential/criteria/EvaluableKeyLengthCredentialCriteria.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/security/credential/criteria/EvaluableKeyLengthCredentialCriteria.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/security/credential/criteria/EvaluableKeyLengthCredentialCriteria.java 17 Aug 2012 15:17:16 -0000 1.1 @@ -0,0 +1,104 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.security.credential.criteria; + +import java.security.Key; + +import org.opensaml.xml.security.SecurityHelper; +import org.opensaml.xml.security.credential.Credential; +import org.opensaml.xml.security.criteria.KeyLengthCriteria; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Instance of evaluable credential criteria for evaluating the credential key length. + */ +public class EvaluableKeyLengthCredentialCriteria implements EvaluableCredentialCriteria { + + /** Logger. */ + private final Logger log = LoggerFactory.getLogger(EvaluableKeyLengthCredentialCriteria.class); + + /** Base criteria. */ + private Integer keyLength; + + /** + * Constructor. + * + * @param criteria the criteria which is the basis for evaluation + */ + public EvaluableKeyLengthCredentialCriteria(KeyLengthCriteria criteria) { + if (criteria == null) { + throw new NullPointerException("Criteria instance may not be null"); + } + keyLength = criteria.getKeyLength(); + } + + /** + * Constructor. + * + * @param newKeyLength the criteria value which is the basis for evaluation + */ + public EvaluableKeyLengthCredentialCriteria(Integer newKeyLength) { + if (newKeyLength == null) { + throw new IllegalArgumentException("Key length may not be null"); + } + keyLength = newKeyLength; + } + + /** {@inheritDoc} */ + public Boolean evaluate(Credential target) { + if (target == null) { + log.error("Credential target was null"); + return null; + } + Key key = getKey(target); + if (key == null) { + log.info("Could not evaluate criteria, credential contained no key"); + return null; + } + Integer length = SecurityHelper.getKeyLength(key); + if (length == null) { + log.info("Could not evaluate criteria, can not determine length of key"); + return null; + } + + Boolean result = keyLength.equals(length); + return result; + } + + /** + * Get the key contained within the credential. + * + * @param credential the credential containing a key + * @return the key from the credential + */ + private Key getKey(Credential credential) { + if (credential.getPublicKey() != null) { + return credential.getPublicKey(); + } else if (credential.getSecretKey() != null) { + return credential.getSecretKey(); + } else if (credential.getPrivateKey() != null) { + // There should have been a corresponding public key, but just in case... + return credential.getPrivateKey(); + } else { + return null; + } + + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/security/credential/criteria/EvaluableKeyNameCredentialCriteria.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/security/credential/criteria/EvaluableKeyNameCredentialCriteria.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/security/credential/criteria/EvaluableKeyNameCredentialCriteria.java 17 Aug 2012 15:17:16 -0000 1.1 @@ -0,0 +1,75 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.security.credential.criteria; + +import org.opensaml.xml.security.credential.Credential; +import org.opensaml.xml.security.criteria.KeyNameCriteria; +import org.opensaml.xml.util.DatatypeHelper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Instance of evaluable credential criteria for evaluating credential key names. + */ +public class EvaluableKeyNameCredentialCriteria implements EvaluableCredentialCriteria { + + /** Logger. */ + private final Logger log = LoggerFactory.getLogger(EvaluableKeyNameCredentialCriteria.class); + + /** Base criteria. */ + private String keyName; + + /** + * Constructor. + * + * @param criteria the criteria which is the basis for evaluation + */ + public EvaluableKeyNameCredentialCriteria(KeyNameCriteria criteria) { + if (criteria == null) { + throw new NullPointerException("Criteria instance may not be null"); + } + keyName = criteria.getKeyName(); + } + + /** + * Constructor. + * + * @param newKeyName the criteria value which is the basis for evaluation + */ + public EvaluableKeyNameCredentialCriteria(String newKeyName) { + if (DatatypeHelper.isEmpty(newKeyName)) { + throw new IllegalArgumentException("Key name may not be null"); + } + keyName = newKeyName; + } + + /** {@inheritDoc} */ + public Boolean evaluate(Credential target) { + if (target == null) { + log.error("Credential target was null"); + return null; + } + if (target.getKeyNames().isEmpty()) { + log.info("Could not evaluate criteria, credential contained no key names"); + return null; + } + Boolean result = target.getKeyNames().contains(keyName); + return result; + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/security/credential/criteria/EvaluablePublicKeyCredentialCriteria.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/security/credential/criteria/EvaluablePublicKeyCredentialCriteria.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/security/credential/criteria/EvaluablePublicKeyCredentialCriteria.java 17 Aug 2012 15:17:16 -0000 1.1 @@ -0,0 +1,79 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.security.credential.criteria; + +import java.security.PublicKey; + +import org.opensaml.xml.security.credential.Credential; +import org.opensaml.xml.security.criteria.PublicKeyCriteria; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Instance of evaluable credential criteria for evaluating whether a credential contains a particular + * public key. + */ +public class EvaluablePublicKeyCredentialCriteria implements EvaluableCredentialCriteria { + + /** Logger. */ + private final Logger log = LoggerFactory.getLogger(EvaluablePublicKeyCredentialCriteria.class); + + /** Base criteria. */ + private PublicKey publicKey; + + /** + * Constructor. + * + * @param criteria the criteria which is the basis for evaluation + */ + public EvaluablePublicKeyCredentialCriteria(PublicKeyCriteria criteria) { + if (criteria == null) { + throw new NullPointerException("Criteria instance may not be null"); + } + publicKey = criteria.getPublicKey(); + } + + /** + * Constructor. + * + * @param newPublicKey the criteria value which is the basis for evaluation + */ + public EvaluablePublicKeyCredentialCriteria(PublicKey newPublicKey) { + if (newPublicKey == null) { + throw new IllegalArgumentException("Public key may not be null"); + } + publicKey = newPublicKey; + } + + /** {@inheritDoc} */ + public Boolean evaluate(Credential target) { + if (target == null) { + log.error("Credential target was null"); + return null; + } + PublicKey key = target.getPublicKey(); + if (key == null) { + log.info("Credential contained no public key, does not satisfy public key criteria"); + return Boolean.FALSE; + } + + Boolean result = publicKey.equals(key); + return result; + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/security/credential/criteria/EvaluableUsageCredentialCriteria.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/security/credential/criteria/EvaluableUsageCredentialCriteria.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/security/credential/criteria/EvaluableUsageCredentialCriteria.java 17 Aug 2012 15:17:16 -0000 1.1 @@ -0,0 +1,91 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.security.credential.criteria; + +import org.opensaml.xml.security.credential.Credential; +import org.opensaml.xml.security.credential.UsageType; +import org.opensaml.xml.security.criteria.UsageCriteria; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Instance of evaluable credential criteria for evaluating whether a credential contains a particular usage specifier. + */ +public class EvaluableUsageCredentialCriteria implements EvaluableCredentialCriteria { + + /** Logger. */ + private final Logger log = LoggerFactory.getLogger(EvaluableUsageCredentialCriteria.class); + + /** Base criteria. */ + private UsageType usage; + + /** + * Constructor. + * + * @param criteria the criteria which is the basis for evaluation + */ + public EvaluableUsageCredentialCriteria(UsageCriteria criteria) { + if (criteria == null) { + throw new NullPointerException("Criteria instance may not be null"); + } + usage = criteria.getUsage(); + } + + /** + * Constructor. + * + * @param newUsage the criteria value which is the basis for evaluation + */ + public EvaluableUsageCredentialCriteria(UsageType newUsage) { + if (newUsage == null) { + throw new IllegalArgumentException("Usage may not be null"); + } + usage = newUsage; + } + + /** {@inheritDoc} */ + public Boolean evaluate(Credential target) { + if (target == null) { + log.error("Credential target was null"); + return null; + } + UsageType credUsage = target.getUsageType(); + if (credUsage == null) { + log.info("Could not evaluate criteria, credential contained no usage specifier"); + return null; + } + + Boolean result = matchUsage(credUsage, usage); + return result; + } + + /** + * Match usage enum type values from credential and criteria. + * + * @param credentialUsage the usage value from the credential + * @param criteriaUsage the usage value from the criteria + * @return true if the two usage specifiers match for purposes of resolving credentials, false otherwise + */ + protected boolean matchUsage(UsageType credentialUsage, UsageType criteriaUsage) { + if (credentialUsage == UsageType.UNSPECIFIED || criteriaUsage == UsageType.UNSPECIFIED) { + return true; + } + return credentialUsage == criteriaUsage; + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/security/credential/criteria/EvaluableX509CertSelectorCredentialCriteria.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/security/credential/criteria/EvaluableX509CertSelectorCredentialCriteria.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/security/credential/criteria/EvaluableX509CertSelectorCredentialCriteria.java 17 Aug 2012 15:17:16 -0000 1.1 @@ -0,0 +1,75 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.security.credential.criteria; + +import java.security.cert.X509CertSelector; +import java.security.cert.X509Certificate; + +import org.opensaml.xml.security.credential.Credential; +import org.opensaml.xml.security.x509.X509Credential; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Instance of evaluable credential criteria for evaluating whether a credential's certificate meets the criteria + * specified by an instance of {@link X509CertSelector}. + * + */ +public class EvaluableX509CertSelectorCredentialCriteria implements EvaluableCredentialCriteria { + + /** Logger. */ + private final Logger log = LoggerFactory.getLogger(EvaluableX509CertSelectorCredentialCriteria.class); + + /** Base criteria. */ + private X509CertSelector certSelector; + + /** + * Constructor. + * + * @param newSelector the new X509 cert selector + */ + public EvaluableX509CertSelectorCredentialCriteria(X509CertSelector newSelector) { + if (newSelector == null) { + throw new IllegalArgumentException("X509 cert selector may not be null"); + } + certSelector = newSelector; + } + + /** {@inheritDoc} */ + public Boolean evaluate(Credential target) { + if (target == null) { + log.error("Credential target was null"); + return null; + } + if (!(target instanceof X509Credential)) { + log.info("Credential is not an X509Credential, can not evaluate X509CertSelector criteria"); + return Boolean.FALSE; + } + X509Credential x509Cred = (X509Credential) target; + + X509Certificate entityCert = x509Cred.getEntityCertificate(); + if (entityCert == null) { + log.info("X509Credential did not contain an entity certificate, can not evaluate X509CertSelector criteria"); + return Boolean.FALSE; + } + + Boolean result = certSelector.match(entityCert); + return result; + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/security/credential/criteria/EvaluableX509IssuerSerialCredentialCriteria.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/security/credential/criteria/EvaluableX509IssuerSerialCredentialCriteria.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/security/credential/criteria/EvaluableX509IssuerSerialCredentialCriteria.java 17 Aug 2012 15:17:16 -0000 1.1 @@ -0,0 +1,98 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.security.credential.criteria; + +import java.math.BigInteger; +import java.security.cert.X509Certificate; + +import javax.security.auth.x500.X500Principal; + +import org.opensaml.xml.security.credential.Credential; +import org.opensaml.xml.security.x509.X509Credential; +import org.opensaml.xml.security.x509.X509IssuerSerialCriteria; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Instance of evaluable credential criteria for evaluating whether a credential's certificate contains a particular + * issuer name and serial number. + */ +public class EvaluableX509IssuerSerialCredentialCriteria implements EvaluableCredentialCriteria { + + /** Logger. */ + private final Logger log = LoggerFactory.getLogger(EvaluableX509IssuerSerialCredentialCriteria.class); + + /** Base criteria. */ + private X500Principal issuer; + + /** Base criteria. */ + private BigInteger serialNumber; + + /** + * Constructor. + * + * @param criteria the criteria which is the basis for evaluation + */ + public EvaluableX509IssuerSerialCredentialCriteria(X509IssuerSerialCriteria criteria) { + if (criteria == null) { + throw new NullPointerException("Criteria instance may not be null"); + } + issuer = criteria.getIssuerName(); + serialNumber = criteria.getSerialNumber(); + } + + /** + * Constructor. + * + * @param newIssuer the issuer name criteria value which is the basis for evaluation + * @param newSerialNumber the serial number criteria value which is the basis for evaluation + */ + public EvaluableX509IssuerSerialCredentialCriteria(X500Principal newIssuer, BigInteger newSerialNumber) { + if (newIssuer == null || newSerialNumber == null) { + throw new IllegalArgumentException("Issuer and serial number may not be null"); + } + issuer = newIssuer; + serialNumber = newSerialNumber; + } + + /** {@inheritDoc} */ + public Boolean evaluate(Credential target) { + if (target == null) { + log.error("Credential target was null"); + return null; + } + if (!(target instanceof X509Credential)) { + log.info("Credential is not an X509Credential, does not satisfy issuer name and serial number criteria"); + return Boolean.FALSE; + } + X509Credential x509Cred = (X509Credential) target; + + X509Certificate entityCert = x509Cred.getEntityCertificate(); + if (entityCert == null) { + log.info("X509Credential did not contain an entity certificate, does not satisfy criteria"); + return Boolean.FALSE; + } + + if (!entityCert.getIssuerX500Principal().equals(issuer)) { + return false; + } + Boolean result = entityCert.getSerialNumber().equals(serialNumber); + return result; + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/security/credential/criteria/EvaluableX509SubjectKeyIdentifierCredentialCriteria.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/security/credential/criteria/EvaluableX509SubjectKeyIdentifierCredentialCriteria.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/security/credential/criteria/EvaluableX509SubjectKeyIdentifierCredentialCriteria.java 17 Aug 2012 15:17:16 -0000 1.1 @@ -0,0 +1,94 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.security.credential.criteria; + +import java.security.cert.X509Certificate; +import java.util.Arrays; + +import org.opensaml.xml.security.credential.Credential; +import org.opensaml.xml.security.x509.X509Credential; +import org.opensaml.xml.security.x509.X509SubjectKeyIdentifierCriteria; +import org.opensaml.xml.security.x509.X509Util; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Instance of evaluable credential criteria for evaluating whether a credential's certificate contains a particular + * subject key identifier. + */ +public class EvaluableX509SubjectKeyIdentifierCredentialCriteria implements EvaluableCredentialCriteria { + + /** Logger. */ + private final Logger log = LoggerFactory.getLogger(EvaluableX509SubjectKeyIdentifierCredentialCriteria.class); + + /** Base criteria. */ + private byte[] ski; + + /** + * Constructor. + * + * @param criteria the criteria which is the basis for evaluation + */ + public EvaluableX509SubjectKeyIdentifierCredentialCriteria(X509SubjectKeyIdentifierCriteria criteria) { + if (criteria == null) { + throw new NullPointerException("Criteria instance may not be null"); + } + ski = criteria.getSubjectKeyIdentifier(); + } + + /** + * Constructor. + * + * @param newSKI the criteria value which is the basis for evaluation + */ + public EvaluableX509SubjectKeyIdentifierCredentialCriteria(byte[] newSKI) { + if (newSKI == null || newSKI.length == 0) { + throw new IllegalArgumentException("Subject key identifier may not be null or empty"); + } + ski = newSKI; + } + + /** {@inheritDoc} */ + public Boolean evaluate(Credential target) { + if (target == null) { + log.error("Credential target was null"); + return null; + } + if (! (target instanceof X509Credential)) { + log.info("Credential is not an X509Credential, does not satisfy subject key identifier criteria"); + return Boolean.FALSE; + } + X509Credential x509Cred = (X509Credential) target; + + X509Certificate entityCert = x509Cred.getEntityCertificate(); + if (entityCert == null) { + log.info("X509Credential did not contain an entity certificate, does not satisfy criteria"); + return Boolean.FALSE; + } + + byte[] credSKI = X509Util.getSubjectKeyIdentifier(entityCert); + if (credSKI == null || credSKI.length == 0) { + log.info("Could not evaluate criteria, certificate contained no subject key identifier extension"); + return null; + } + + Boolean result = Arrays.equals(ski, credSKI); + return result; + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/security/credential/criteria/EvaluableX509SubjectNameCredentialCriteria.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/security/credential/criteria/EvaluableX509SubjectNameCredentialCriteria.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/security/credential/criteria/EvaluableX509SubjectNameCredentialCriteria.java 17 Aug 2012 15:17:16 -0000 1.1 @@ -0,0 +1,88 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.security.credential.criteria; + +import java.security.cert.X509Certificate; + +import javax.security.auth.x500.X500Principal; + +import org.opensaml.xml.security.credential.Credential; +import org.opensaml.xml.security.x509.X509Credential; +import org.opensaml.xml.security.x509.X509SubjectNameCriteria; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Instance of evaluable credential criteria for evaluating whether a credential's certificate contains a particular + * subject name. + */ +public class EvaluableX509SubjectNameCredentialCriteria implements EvaluableCredentialCriteria { + + /** Logger. */ + private final Logger log = LoggerFactory.getLogger(EvaluableX509SubjectNameCredentialCriteria.class); + + /** Base criteria. */ + private X500Principal subjectName; + + /** + * Constructor. + * + * @param criteria the criteria which is the basis for evaluation + */ + public EvaluableX509SubjectNameCredentialCriteria(X509SubjectNameCriteria criteria) { + if (criteria == null) { + throw new NullPointerException("Criteria instance may not be null"); + } + subjectName = criteria.getSubjectName(); + } + + /** + * Constructor. + * + * @param newSubjectName the subject name criteria value which is the basis for evaluation + */ + public EvaluableX509SubjectNameCredentialCriteria(X500Principal newSubjectName) { + if (newSubjectName == null) { + throw new IllegalArgumentException("Subject name may not be null"); + } + subjectName = newSubjectName; + } + + /** {@inheritDoc} */ + public Boolean evaluate(Credential target) { + if (target == null) { + log.error("Credential target was null"); + return null; + } + if (!(target instanceof X509Credential)) { + log.info("Credential is not an X509Credential, does not satisfy subject name criteria"); + return Boolean.FALSE; + } + X509Credential x509Cred = (X509Credential) target; + + X509Certificate entityCert = x509Cred.getEntityCertificate(); + if (entityCert == null) { + log.info("X509Credential did not contain an entity certificate, does not satisfy criteria"); + return Boolean.FALSE; + } + + Boolean result = entityCert.getSubjectX500Principal().equals(subjectName); + return result; + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/security/credential/criteria/package.html =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/security/credential/criteria/package.html,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/security/credential/criteria/package.html 17 Aug 2012 15:17:16 -0000 1.1 @@ -0,0 +1,15 @@ + + +

+Implementations of {@link org.opensaml.xml.security.EvaluableCriteria} where the +parameterized evaluation target type is {@link org.opensaml.xml.security.credential.Credential}. This is also +represented by the marker interface {@link org.opensaml.xml.security.credential.criteria.EvaluableCredentialCriteria}. +

+

+Also contains {@link org.opensaml.xml.security.credential.criteria.EvaluableCredentialCriteriaRegistry}, +which is capable of looking up and returning a particular implementation of EvaluableCredentialCriteria +which should be used to evaluate a given (non-evaluable) {@link org.opensaml.xml.security.Criteria} against +a Credential. +

+ + Index: 3rdParty_sources/xmltooling/org/opensaml/xml/security/criteria/EntityIDCriteria.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/security/criteria/EntityIDCriteria.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/security/criteria/EntityIDCriteria.java 17 Aug 2012 15:17:06 -0000 1.1 @@ -0,0 +1,71 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.security.criteria; + +import org.opensaml.xml.security.Criteria; +import org.opensaml.xml.util.DatatypeHelper; + +/** + * An implementation of {@link Criteria} which specifies criteria identifying a + * particular entity. + * + * Note that when used as a credential criteria for a credential resolver, the entity ID is the entity which owns + * the resolved credential. This entity ID may represent either a local entity (self) or remote entity, depending + * on the use case, e.g. in resolution of signature verification credentials, the owner entity ID + * would be a remote peer; in resolution of decryption credentials, the owner entity ID would be + * a local entity ID. + * + * See also {@link PeerEntityIDCriteria}. + */ +public final class EntityIDCriteria implements Criteria { + + /** Entity ID criteria. */ + private String entityID; + + /** + * Constructor. + * + * @param entity the entity ID represented by the criteria + */ + public EntityIDCriteria(String entity) { + setEntityID(entity); + } + + /** + * Get the entity ID represented by the criteria. + * + * @return the primary entity ID. + */ + public String getEntityID() { + return entityID; + } + + /** + * Set the entity ID represented by the criteria. + * + * @param entity The entityID to set. + */ + public void setEntityID(String entity) { + String trimmed = DatatypeHelper.safeTrimOrNullString(entity); + if (trimmed == null) { + throw new IllegalArgumentException("Entity ID criteria must be supplied"); + } + entityID = trimmed; + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/security/criteria/KeyAlgorithmCriteria.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/security/criteria/KeyAlgorithmCriteria.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/security/criteria/KeyAlgorithmCriteria.java 17 Aug 2012 15:17:06 -0000 1.1 @@ -0,0 +1,61 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.security.criteria; + +import org.opensaml.xml.security.Criteria; +import org.opensaml.xml.util.DatatypeHelper; + +/** + * An implementation of {@link Criteria} which specifies key algorithm criteria. + */ +public final class KeyAlgorithmCriteria implements Criteria { + + /** Key algorithm type of resolved credentials. */ + private String keyAlgorithm; + + /** + * Constructor. + * + * @param algorithm key algorithm + */ + public KeyAlgorithmCriteria(String algorithm) { + setKeyAlgorithm(algorithm); + } + + /** + * Get the key algorithm criteria. + * + * @return returns the keyAlgorithm. + */ + public String getKeyAlgorithm() { + return keyAlgorithm; + } + + /** + * Set the key algorithm criteria. + * + * @param algorithm The keyAlgorithm to set. + */ + public void setKeyAlgorithm(String algorithm) { + if (DatatypeHelper.isEmpty(algorithm)) { + throw new IllegalArgumentException("Key algorithm criteria value must be supplied"); + } + keyAlgorithm = DatatypeHelper.safeTrimOrNullString(algorithm); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/security/criteria/KeyLengthCriteria.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/security/criteria/KeyLengthCriteria.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/security/criteria/KeyLengthCriteria.java 17 Aug 2012 15:17:06 -0000 1.1 @@ -0,0 +1,60 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.security.criteria; + +import org.opensaml.xml.security.Criteria; + +/** + * An implementation of {@link Criteria} which specifies key length criteria. + */ +public final class KeyLengthCriteria implements Criteria { + + /** Key length of resolved credentials. */ + private Integer keyLength; + + /** + * Constructor. + * + * @param length key length + */ + public KeyLengthCriteria(Integer length) { + setKeyLength(length); + } + + /** + * Get the key length. + * + * @return Returns the keyLength. + */ + public Integer getKeyLength() { + return keyLength; + } + + /** + * Set the key length. + * + * @param length The keyLength to set. + */ + public void setKeyLength(Integer length) { + if (length == null) { + throw new IllegalArgumentException("Key length criteria value must be supplied"); + } + keyLength = length; + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/security/criteria/KeyNameCriteria.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/security/criteria/KeyNameCriteria.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/security/criteria/KeyNameCriteria.java 17 Aug 2012 15:17:06 -0000 1.1 @@ -0,0 +1,61 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.security.criteria; + +import org.opensaml.xml.security.Criteria; +import org.opensaml.xml.util.DatatypeHelper; + +/** + * An implementation of {@link Criteria} which specifies key name criteria. + */ +public final class KeyNameCriteria implements Criteria { + + /** Key name of resolved credentials. */ + private String keyName; + + /** + * Constructor. + * + * @param name key name + */ + public KeyNameCriteria(String name) { + setKeyName(name); + } + + /** + * Get the key name criteria. + * + * @return Returns the keyName. + */ + public String getKeyName() { + return keyName; + } + + /** + * Set the key name criteria. + * + * @param name The keyName to set. + */ + public void setKeyName(String name) { + if (DatatypeHelper.isEmpty(name)) { + throw new IllegalArgumentException("Key name criteria value must be supplied"); + } + keyName = DatatypeHelper.safeTrimOrNullString(name); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/security/criteria/PeerEntityIDCriteria.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/security/criteria/PeerEntityIDCriteria.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/security/criteria/PeerEntityIDCriteria.java 17 Aug 2012 15:17:06 -0000 1.1 @@ -0,0 +1,68 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.security.criteria; + +import org.opensaml.xml.security.Criteria; +import org.opensaml.xml.util.DatatypeHelper; + +/** + * An implementation of {@link Criteria} which specifies criteria pertaining + * to peer entity IDs. This is typically used only in conjunction with a + * {@link EntityIDCriteria}, where the peer is interpreted to be relative + * to that primary entity ID. In this sense it serves to scope the primary entity ID. + * + * Note that the peer entity ID may be either local or remote, + * depending on whether the associated primary entity ID is remote or local. + */ +public final class PeerEntityIDCriteria implements Criteria { + + /** Peer entity ID criteria. */ + private String peerID; + + /** + * Constructor. + * + * @param peer the entity ID which is the peer relative to a primary entity ID + */ + public PeerEntityIDCriteria(String peer) { + setPeerID(peer); + } + + /** + * Get the entity ID which is the peer relative to a primary entity ID. + * + * @return the peer entity ID. + */ + public String getPeerID() { + return peerID; + } + + /** + * Set the entity ID which is the peer relative to a primary entity ID. + * + * @param peer The peerID to set. + */ + public void setPeerID(String peer) { + String trimmed = DatatypeHelper.safeTrimOrNullString(peer); + if (trimmed == null) { + throw new IllegalArgumentException("Peer entity ID criteria must be supplied"); + } + peerID = trimmed; + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/security/criteria/PublicKeyCriteria.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/security/criteria/PublicKeyCriteria.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/security/criteria/PublicKeyCriteria.java 17 Aug 2012 15:17:06 -0000 1.1 @@ -0,0 +1,62 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.security.criteria; + +import java.security.PublicKey; + +import org.opensaml.xml.security.Criteria; + +/** + * An implementation of {@link Criteria} which specifies public key criteria. + */ +public final class PublicKeyCriteria implements Criteria { + + /** Specifier of public key associated with resolved credentials. */ + private PublicKey publicKey; + + /** + * Constructor. + * + * @param pubKey public key + */ + public PublicKeyCriteria(PublicKey pubKey) { + setPublicKey(pubKey); + } + + /** + * Get the public key criteria. + * + * @return Returns the publicKey. + */ + public PublicKey getPublicKey() { + return publicKey; + } + + /** + * Set the public key criteria. + * + * @param key The publicKey to set. + */ + public void setPublicKey(PublicKey key) { + if (key == null) { + throw new IllegalArgumentException("Public key criteria value must be supplied"); + } + publicKey = key; + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/security/criteria/UsageCriteria.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/security/criteria/UsageCriteria.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/security/criteria/UsageCriteria.java 17 Aug 2012 15:17:06 -0000 1.1 @@ -0,0 +1,64 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.security.criteria; + +import org.opensaml.xml.security.Criteria; +import org.opensaml.xml.security.credential.UsageType; + + +/** + * An implementation of {@link Criteria} which specifies criteria pertaining + * usage of the resolved credential. + */ +public final class UsageCriteria implements Criteria { + + /** Key usage type of resolved credentials. */ + private UsageType credUsage; + + /** + * Constructor. + * + * @param usage the usage for which a credential is intended + */ + public UsageCriteria(UsageType usage) { + setUsage(usage); + } + + /** + * Get the key usage criteria. + * + * @return Returns the usage. + */ + public UsageType getUsage() { + return credUsage; + } + + /** + * Set the key usage criteria. + * + * @param usage The usage to set. + */ + public void setUsage(UsageType usage) { + if (usage != null) { + credUsage = usage; + } else { + credUsage = UsageType.UNSPECIFIED; + } + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/security/criteria/package.html =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/security/criteria/package.html,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/security/criteria/package.html 17 Aug 2012 15:17:06 -0000 1.1 @@ -0,0 +1,15 @@ + + +

+Classes which model the abstract notion of a 'criteria'. Criteria are most often used as input to a +{@link org.opensaml.xml.security.Resolver}. Criteria are typically used by resolvers in an +resolver-specific manner to either lookup or extract information from a source, +or to constrain or filter the type of information that will be returned. +

+

+This package provides some implementations of {@link org.opensaml.xml.security.Criteria} which +may have general applicability throughout the library. Criteria implementations which are more +specialized in nature may be found in other packages, such as {@link org.opensaml.xml.security.x509}. +

+ + Index: 3rdParty_sources/xmltooling/org/opensaml/xml/security/keyinfo/BasicProviderKeyInfoCredentialResolver.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/security/keyinfo/BasicProviderKeyInfoCredentialResolver.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/security/keyinfo/BasicProviderKeyInfoCredentialResolver.java 17 Aug 2012 15:17:13 -0000 1.1 @@ -0,0 +1,443 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.security.keyinfo; + +import java.security.Key; +import java.security.KeyException; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import javax.crypto.SecretKey; + +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.security.CriteriaSet; +import org.opensaml.xml.security.SecurityException; +import org.opensaml.xml.security.SecurityHelper; +import org.opensaml.xml.security.credential.AbstractCriteriaFilteringCredentialResolver; +import org.opensaml.xml.security.credential.BasicCredential; +import org.opensaml.xml.security.credential.Credential; +import org.opensaml.xml.signature.KeyInfo; +import org.opensaml.xml.signature.KeyName; +import org.opensaml.xml.signature.KeyValue; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Implementation of {@link KeyInfoCredentialResolver} which resolves credentials based on a {@link KeyInfo} element + * using a configured list of {@link KeyInfoProvider}'s and optional post-processing hooks. + * + *

+ * The majority of the processing of the KeyInfo and extraction of {@link Credential}'s from the KeyInfo is handled by + * instances of {@link KeyInfoProvider}. An ordered list of KeyInfoProviders must be supplied to the resolver when it + * is constructed. + *

+ * + *

+ * This resolver requires a {@link KeyInfoCriteria} to be supplied as the resolution criteria. It is permissible, + * however, for the criteria's KeyInfo data object to be null. This allows for more convenient processing logic, for + * example, in cases when a parent element allows an optional KeyInfo and when in fact a given instance does not contain + * one. Specialized subclasses of this resolver may still attempt to return credentials in an implementation or + * context-specific manner, as described below. + *

+ * + *

+ * Processing of the supplied KeyInfo element proceeds as follows: + *

    + *
  1. A {@link KeyInfoResolutionContext} is instantiated. This resolution context is used to hold state shared amongst + * all the providers and processing hooks which run within the resolver.
  2. + *
  3. This resolution context is initialized and populated with the actual KeyInfo object being processed as well as + * the values of any {@link KeyName} child elements present.
  4. + *
  5. An attempt is then made to resolve a credential from any {@link KeyValue} child elements as described for + * {@link #resolveKeyValue(KeyInfoResolutionContext, CriteriaSet, List)} If a credential is so resolved, its key will + * also be placed in the resolution context
  6. + *
  7. The remaining (non-KeyValue) children are then processed in document order. Each child element is processed by + * the registered providers in provider list order. The credential or credentials resolved by the first provider to + * successfully do so are added to the effective set of credentials returned by the resolver, and processing of that + * child element terminates. Processing continues with the next child element.
  8. + *
  9. At this point all KeyInfo children have been processed. If the effective set of credentials to return is empty, + * and if a key was resolved from a KeyValue element and is available in the resolution context, a basic credential is + * built with that key and is added to the effective set. Since the KeyInfo may have a plain KeyValue representation of + * the key represented by the KeyInfo, in addition to a more specific key type/container (and hence credential) + * representation, this technique avoids the unnecessary return of duplicate keys, returning only the more specific + * credential representation of the key.
  10. + *
  11. A post-processing hook is then called: {@link #postProcess(KeyInfoResolutionContext, CriteriaSet, List)}. The + * default implementation is a no-op. This is an extension point by which subclasses may implement custom + * post-processing of the effective credential set to be returned. One example use case is when the KeyInfo being + * processed represents the public aspects (e.g. public key, or a key name or other identifier) of an encryption key + * belonging to the resolving entity. The resolved public keys and other resolution context information may be used to + * further resolve the credential or credentials containing the associated decryption key (i.e. a private or symmetric + * key). For an example of such an implementation, see {@link LocalKeyInfoCredentialResolver}
  12. + *
  13. Finally, if no credentials have been otherwise resolved, a final post-processing hook is called: + * {@link #postProcessEmptyCredentials(KeyInfoResolutionContext, CriteriaSet, List)}. The default implementation is a + * no-op. This is an extension point by which subclasses may implement custom logic to resolve credentials in an + * implementation or context-specific manner, if no other mechanism has succeeded. Example usages might be to return a + * default set of credentials, or to use non-KeyInfo-derived criteria or contextual information to determine the + * credential or credentials to return.
  14. + *
+ *

+ * + */ +public class BasicProviderKeyInfoCredentialResolver extends AbstractCriteriaFilteringCredentialResolver implements + KeyInfoCredentialResolver { + + /** Class logger. */ + private final Logger log = LoggerFactory.getLogger(BasicProviderKeyInfoCredentialResolver.class); + + /** List of KeyInfo providers that are registered on this instance. */ + private List providers; + + /** + * Constructor. + * + * @param keyInfoProviders the list of KeyInfoProvider's to use in this resolver + */ + public BasicProviderKeyInfoCredentialResolver(List keyInfoProviders) { + super(); + + providers = new ArrayList(); + providers.addAll(keyInfoProviders); + } + + /** + * Return the list of the KeyInfoProvider instances used in this resolver configuration. + * + * @return the list of providers configured for this resolver instance + */ + protected List getProviders() { + return providers; + } + + /** {@inheritDoc} */ + protected Iterable resolveFromSource(CriteriaSet criteriaSet) throws SecurityException { + KeyInfoCriteria kiCriteria = criteriaSet.get(KeyInfoCriteria.class); + if (kiCriteria == null) { + log.error("No KeyInfo criteria supplied, resolver could not process"); + throw new SecurityException("Credential criteria set did not contain an instance of" + + "KeyInfoCredentialCriteria"); + } + KeyInfo keyInfo = kiCriteria.getKeyInfo(); + + // This will be the list of credentials to return. + List credentials = new ArrayList(); + + KeyInfoResolutionContext kiContext = new KeyInfoResolutionContext(credentials); + + // Note: we allow KeyInfo to be null to handle case where application context, + // other accompanying criteria, etc, should be used to resolve credentials via hooks below. + if (keyInfo != null) { + processKeyInfo(keyInfo, kiContext, criteriaSet, credentials); + } else { + log.info("KeyInfo was null, any credentials will be resolved by post-processing hooks only"); + } + + // Postprocessing hook + postProcess(kiContext, criteriaSet, credentials); + + // Final empty credential hook + if (credentials.isEmpty()) { + log.debug("No credentials were found, calling empty credentials post-processing hook"); + postProcessEmptyCredentials(kiContext, criteriaSet, credentials); + } + + log.debug("A total of {} credentials were resolved", credentials.size()); + return credentials; + } + + /** + * The main processing logic implemented by this resolver. + * + * @param keyInfo the KeyInfo being processed + * @param kiContext KeyInfo resolution context + * @param criteriaSet the credential criteria used to resolve credentials + * @param credentials the list which will store the resolved credentials + * @throws SecurityException thrown if there is an error during processing + */ + private void processKeyInfo(KeyInfo keyInfo, KeyInfoResolutionContext kiContext, CriteriaSet criteriaSet, + List credentials) throws SecurityException { + + // Initialize the resolution context that will be used by the provider plugins. + // This processes the KeyName and the KeyValue children, if either are present. + initResolutionContext(kiContext, keyInfo, criteriaSet); + + // Store these off so we later use the original values, + // unmodified by other providers which later run. + Key keyValueKey = kiContext.getKey(); + HashSet keyNames = new HashSet(); + keyNames.addAll(kiContext.getKeyNames()); + + // Now process all (non-KeyValue) children + processKeyInfoChildren(kiContext, criteriaSet, credentials); + + if (credentials.isEmpty() && keyValueKey != null) { + // Add the credential based on plain KeyValue if no more specifc cred type was found + Credential keyValueCredential = buildBasicCredential(keyValueKey, keyNames); + if (keyValueCredential != null) { + log.debug("No credentials were extracted by registered non-KeyValue handling providers, " + + "adding KeyValue credential to returned credential set"); + credentials.add(keyValueCredential); + } + } + } + + /** + * Hook for subclasses to do post-processing of the credential set after all KeyInfo children have been processed. + * + * For example, the previously resolved credentials might be used to index into a store of local credentials, where + * the index is a key name or the public half of a key pair extracted from the KeyInfo. + * + * @param kiContext KeyInfo resolution context + * @param criteriaSet the credential criteria used to resolve credentials + * @param credentials the list which will store the resolved credentials + * @throws SecurityException thrown if there is an error during processing + */ + protected void postProcess(KeyInfoResolutionContext kiContext, CriteriaSet criteriaSet, List credentials) + throws SecurityException { + + } + + /** + * Hook for processing the case where no credentials were returned by any resolution method by any provider, nor by + * the processing of the {@link #postProcess(KeyInfoResolutionContext, CriteriaSet, List)} hook. + * + * @param kiContext KeyInfo resolution context + * @param criteriaSet the credential criteria used to resolve credentials + * @param credentials the list which will store the resolved credentials + * + * @throws SecurityException thrown if there is an error during processing + */ + protected void postProcessEmptyCredentials(KeyInfoResolutionContext kiContext, CriteriaSet criteriaSet, + List credentials) throws SecurityException { + + } + + /** + * Use registered providers to process the non-KeyValue children of KeyInfo. + * + * Each child element is processed in document order. Each child element is processed by each provider in the + * ordered list of providers. The credential or credentials resolved by the first provider to successfully do so are + * added to the effective set resolved by the KeyInfo resolver. + * + * @param kiContext KeyInfo resolution context + * @param criteriaSet the credential criteria used to resolve credentials + * @param credentials the list which will store the resolved credentials + * @throws SecurityException thrown if there is a provider error processing the KeyInfo children + */ + protected void processKeyInfoChildren(KeyInfoResolutionContext kiContext, CriteriaSet criteriaSet, + List credentials) throws SecurityException { + + for (XMLObject keyInfoChild : kiContext.getKeyInfo().getXMLObjects()) { + + if (keyInfoChild instanceof KeyValue) { + continue; + } + + log.debug("Processing KeyInfo child with qname: {}", keyInfoChild.getElementQName()); + Collection childCreds = processKeyInfoChild(kiContext, criteriaSet, keyInfoChild); + + if (childCreds != null && !childCreds.isEmpty()) { + credentials.addAll(childCreds); + } else { + // Not really an error or warning if KeyName doesn't produce a credential + if (keyInfoChild instanceof KeyName) { + log.debug("KeyName, with value {}, did not independently produce a credential based on any registered providers", + ((KeyName) keyInfoChild).getValue()); + + } else { + log.warn("No credentials could be extracted from KeyInfo child with qname {} by any registered provider", + keyInfoChild.getElementQName()); + } + } + } + } + + /** + * Process the given KeyInfo child with the registered providers. + * + * The child element is processed by each provider in the ordered list of providers. The credential or credentials + * resolved by the first provider to successfully do so are returned and processing of the child element is + * terminated. + * + * @param kiContext KeyInfo resolution context + * @param criteriaSet the credential criteria used to resolve credentials + * @param keyInfoChild the KeyInfo to evaluate + * @return the collection of resolved credentials, or null + * @throws SecurityException thrown if there is a provider error processing the KeyInfo child + */ + protected Collection processKeyInfoChild(KeyInfoResolutionContext kiContext, CriteriaSet criteriaSet, + XMLObject keyInfoChild) throws SecurityException { + + for (KeyInfoProvider provider : getProviders()) { + + if (!provider.handles(keyInfoChild)) { + log.debug("Provider {} doesn't handle objects of type {}, skipping", provider.getClass().getName(), + keyInfoChild.getElementQName()); + continue; + } + + log.debug("Processing KeyInfo child {} with provider {}", keyInfoChild.getElementQName(), provider + .getClass().getName()); + Collection creds = provider.process(this, keyInfoChild, criteriaSet, kiContext); + + if (creds != null && !creds.isEmpty()) { + log.debug("Credentials successfully extracted from child {} by provider {}", keyInfoChild + .getElementQName(), provider.getClass().getName()); + return creds; + } + } + return null; + } + + /** + * Initialize the resolution context that will be used by the providers. + * + * The supplied KeyInfo object is stored in the context, as well as the values of any {@link KeyName} children + * present. Finally if a credential is resolveble by any registered provider from a plain {@link KeyValue} child, + * the key from that credential is also stored in the context. + * + * @param kiContext KeyInfo resolution context + * @param keyInfo the KeyInfo to evaluate + * @param criteriaSet the credential criteria used to resolve credentials + * @throws SecurityException thrown if there is an error processing the KeyValue children + */ + protected void initResolutionContext(KeyInfoResolutionContext kiContext, KeyInfo keyInfo, CriteriaSet criteriaSet) + throws SecurityException { + + kiContext.setKeyInfo(keyInfo); + + // Extract all KeyNames + kiContext.getKeyNames().addAll(KeyInfoHelper.getKeyNames(keyInfo)); + log.debug("Found {} key names: {}", kiContext.getKeyNames().size(), kiContext.getKeyNames()); + + // Extract the Credential based on the (singular) key from an existing KeyValue(s). + resolveKeyValue(kiContext, criteriaSet, keyInfo.getKeyValues()); + } + + /** + * Resolve the key from any KeyValue element that may be present, and store the resulting key in the resolution + * context. + * + * Each KeyValue element is processed in turn in document order. Each Keyvalue will be processed by each provider in + * the ordered list of registered providers. The key from the first credential successfully resolved from a KeyValue + * will be stored in the resolution context. + * + * Note: This resolver implementation assumes that KeyInfo/KeyValue will not be abused via-a-vis the Signature + * specificiation, and that therefore all KeyValue elements (if there is even more than one) will all resolve to the + * same key value. The KeyInfo might, for example have multiple KeyValue children, containing different + * representations of the same key. Therefore, only the first credential derived from a KeyValue will be be + * utilized. + * + * @param kiContext KeyInfo resolution context + * @param criteriaSet the credential criteria used to resolve credentials + * @param keyValues the KeyValue children to evaluate + * @throws SecurityException thrown if there is an error resolving the key from the KeyValue + */ + protected void resolveKeyValue(KeyInfoResolutionContext kiContext, CriteriaSet criteriaSet, List keyValues) + throws SecurityException { + + for (KeyValue keyValue : keyValues) { + Collection creds = processKeyInfoChild(kiContext, criteriaSet, keyValue); + if (creds != null) { + for (Credential cred : creds) { + Key key = extractKeyValue(cred); + if (key != null) { + kiContext.setKey(key); + log.debug("Found a credential based on a KeyValue having key type: {}", key.getAlgorithm()); + return; + } + } + } + } + } + + /** + * Construct a basic credential containing the specified key and set of key names. + * + * @param key the key to include in the credential + * @param keyNames the key names to include in the credential + * @return a basic credential with the specified key and key names + * @throws SecurityException if there is an error building the credential + */ + protected Credential buildBasicCredential(Key key, Set keyNames) throws SecurityException { + if (key == null) { + log.debug("Key supplied was null, could not build credential"); + return null; + } + + BasicCredential basicCred = new BasicCredential(); + + basicCred.getKeyNames().addAll(keyNames); + + if (key instanceof PublicKey) { + basicCred.setPublicKey((PublicKey) key); + } else if (key instanceof SecretKey) { + basicCred.setSecretKey((SecretKey) key); + } else if (key instanceof PrivateKey) { + // This would be unusual for most KeyInfo use cases, + // but go ahead and try and handle it + PrivateKey privateKey = (PrivateKey) key; + try { + PublicKey publicKey = SecurityHelper.derivePublicKey(privateKey); + if (publicKey != null) { + basicCred.setPublicKey(publicKey); + basicCred.setPrivateKey(privateKey); + } else { + log.error("Failed to derive public key from private key"); + return null; + } + } catch (KeyException e) { + log.error("Could not derive public key from private key", e); + return null; + } + } else { + log.error(String.format("Key was of an unsupported type '%s'", key.getClass().getName())); + return null; + } + + return basicCred; + } + + /** + * Utility method to extract any key that might be present in the specified Credential. + * + * @param cred the Credential to evaluate + * @return the Key contained in the credential, or null if it does not contain a key. + */ + protected Key extractKeyValue(Credential cred) { + if (cred == null) { + return null; + } + if (cred.getPublicKey() != null) { + return cred.getPublicKey(); + } + // This could happen if key is derived, e.g. key agreement, etc + if (cred.getSecretKey() != null) { + return cred.getSecretKey(); + } + // Perhaps unlikely, but go ahead and check + if (cred.getPrivateKey() != null) { + return cred.getPrivateKey(); + } + return null; + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/security/keyinfo/CollectionKeyInfoCredentialResolver.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/security/keyinfo/CollectionKeyInfoCredentialResolver.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/security/keyinfo/CollectionKeyInfoCredentialResolver.java 17 Aug 2012 15:17:14 -0000 1.1 @@ -0,0 +1,92 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.security.keyinfo; + +import java.util.ArrayList; +import java.util.Collection; + +import org.opensaml.xml.security.credential.CollectionCredentialResolver; +import org.opensaml.xml.security.credential.Credential; +import org.opensaml.xml.security.credential.criteria.EvaluableCredentialCriteria; +import org.opensaml.xml.security.credential.criteria.EvaluableCredentialCriteriaRegistry; +import org.opensaml.xml.signature.KeyName; +import org.opensaml.xml.signature.X509SubjectName; + +/** + * An implementation of {@link KeyInfoCredentialResolver} which uses a {@link Collection} as the + * underlying credential source. + * + *

+ * Like the + * {@link CollectionCredentialResolver}, credentials returned are filtered based on any + * {@link EvaluableCredentialCriteria} which may have been present in the specified criteria set, or + * which are resolved by lookup in the {@link EvaluableCredentialCriteriaRegistry}. + *

+ * + *

+ * This implementation may be used to address use cases where use of a + * KeyInfoCredentialResolver is required, but a KeyInfo element containing keys or other keying + * material is not necessarily supplied or expected in an instance document and keys/credentials + * are known in advance (e.g. validation keys belonging to a peer, decryption keys belonging to the caller). + * In this use case, credentials are expected to be resolved from other contextual information, + * including information possibly supplied as criteria to the resolver. Such credentials would be stored + * in and returned from the {@link Collection} managed by this resolver. + *

+ * + *

+ * Note that a KeyInfo element + * passed in a {@link KeyInfoCriteria} in the criteria set is NOT directly processed by this + * implementation in any way as a source for extracting keys or other key-related material. + * However, if the evaluable credential criteria registry described above were + * for example to contain a mapping from KeyInfoCriteria to some type of EvaluableCredentialCriteria, + * where the latter used KeyInfo-derived information as its basis for evaluation of a credential (e.g. + * based on contents of a {@link KeyName} or {@link X509SubjectName}), then such KeyInfo-derived + * evaluable criteria would be used to filter or select the specific credentials that would be returned + * from the underlying credential collection of this resolver. Such KeyInfo-derived evaluable criteria + * may also be specified directly in the criteria set, per the above. + *

+ * + *

+ * This implementation might also be used at the end of a chain of KeyInfoCredentialResolvers in + * order to supply a default, fallback set of credentials, if none could otherwise be resolved. + *

+ * + */ +public class CollectionKeyInfoCredentialResolver extends CollectionCredentialResolver implements + KeyInfoCredentialResolver { + + /** + * Constructor. + * + * An {@link ArrayList} is used as the underlying collection implementation. + * + */ + public CollectionKeyInfoCredentialResolver() { + this(new ArrayList()); + } + + /** + * Constructor. + * + * @param credentials the credential collection which is the backing store for the resolver + */ + public CollectionKeyInfoCredentialResolver(Collection credentials) { + super(credentials); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/security/keyinfo/KeyInfoCredentialContext.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/security/keyinfo/KeyInfoCredentialContext.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/security/keyinfo/KeyInfoCredentialContext.java 17 Aug 2012 15:17:14 -0000 1.1 @@ -0,0 +1,48 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.security.keyinfo; + +import org.opensaml.xml.security.credential.CredentialContext; +import org.opensaml.xml.signature.KeyInfo; + +/** + * Context for credentials resolved from a {@link KeyInfo} element. + */ +public class KeyInfoCredentialContext implements CredentialContext { + + /** The KeyInfo context. */ + private KeyInfo keyInfo; + + /** + * Constructor. + * + * @param ki the KeyInfo context + */ + public KeyInfoCredentialContext(KeyInfo ki) { + keyInfo = ki; + } + + /** + * Get the KeyInfo context from which the credential was derived. + * + * @return the KeyInfo context + */ + public KeyInfo getKeyInfo() { + return keyInfo; + } +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/security/keyinfo/KeyInfoCredentialResolver.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/security/keyinfo/KeyInfoCredentialResolver.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/security/keyinfo/KeyInfoCredentialResolver.java 17 Aug 2012 15:17:14 -0000 1.1 @@ -0,0 +1,32 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.security.keyinfo; + +import org.opensaml.xml.security.credential.CredentialResolver; +import org.opensaml.xml.signature.KeyInfo; + +/** + * Specialized {@link CredentialResolver} marker interface for resolvers which resolve + * credentials based on a {@link KeyInfo} element. + * + * Implementations will typically require an instance of {@link KeyInfoCriteria} within the + * criteria set which is supplied as input to the resolve methods. + */ +public interface KeyInfoCredentialResolver extends CredentialResolver { + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/security/keyinfo/KeyInfoCriteria.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/security/keyinfo/KeyInfoCriteria.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/security/keyinfo/KeyInfoCriteria.java 17 Aug 2012 15:17:13 -0000 1.1 @@ -0,0 +1,62 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.security.keyinfo; + +import org.opensaml.xml.security.Criteria; +import org.opensaml.xml.signature.KeyInfo; + +/** + * An implementation of {@link Criteria} which specifies criteria based + * on the contents of a {@link KeyInfo} element. + */ +public final class KeyInfoCriteria implements Criteria { + + /** The KeyInfo which serves as the source for credential criteria. */ + private KeyInfo keyInfo; + + /** + * Constructor. + * + * @param newKeyInfo the KeyInfo credential criteria to use + */ + public KeyInfoCriteria(KeyInfo newKeyInfo) { + setKeyInfo(newKeyInfo); + } + + /** + * Gets the KeyInfo which is the source of credential criteria. + * + * @return the KeyInfo credential criteria + */ + public KeyInfo getKeyInfo() { + return keyInfo; + } + + /** + * Sets the KeyInfo which is the source of credential criteria. + * + * @param newKeyInfo the KeyInfo to use as credential criteria + * + */ + public void setKeyInfo(KeyInfo newKeyInfo) { + // Note: we allow KeyInfo to be null to handle case where application context, + // other accompanying criteria, etc should be used to resolve credentials. + keyInfo = newKeyInfo; + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/security/keyinfo/KeyInfoGenerator.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/security/keyinfo/KeyInfoGenerator.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/security/keyinfo/KeyInfoGenerator.java 17 Aug 2012 15:17:14 -0000 1.1 @@ -0,0 +1,39 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.security.keyinfo; + +import org.opensaml.xml.security.SecurityException; +import org.opensaml.xml.security.credential.Credential; +import org.opensaml.xml.signature.KeyInfo; + +/** + * Interface for implementations which generate a {@link KeyInfo} based on keying material and other + * information found within a {@link Credential}. + */ +public interface KeyInfoGenerator { + + /** + * Generate a new KeyInfo object based on keying material and other information within a credential. + * + * @param credential the credential containing keying material and possibly other information + * @return a new KeyInfo object + * @throws SecurityException thrown if there is any error generating the new KeyInfo from the credential + */ + public KeyInfo generate(Credential credential) throws SecurityException; + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/security/keyinfo/KeyInfoGeneratorFactory.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/security/keyinfo/KeyInfoGeneratorFactory.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/security/keyinfo/KeyInfoGeneratorFactory.java 17 Aug 2012 15:17:14 -0000 1.1 @@ -0,0 +1,51 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.security.keyinfo; + +import org.opensaml.xml.security.credential.Credential; + +/** + * Interface for factories which produce {@link KeyInfoGenerator} instances. + */ +public interface KeyInfoGeneratorFactory { + + /** + * Get a new instance of the generator type produced by the factory. + * + * @return a new KeyInfoGenerator instance + */ + public KeyInfoGenerator newInstance(); + + /** + * Check whether the generators produced by this factory can handle the specified credential. + * + * @param credential the credential to evaluate + * @return true if the generators produced by this factory can handle the type of the specified credential, + * false otherwise + */ + public boolean handles(Credential credential); + + /** + * Get the type (interface) of the specific type of credential handled by generators produced by + * this factory. Primarily used as an index by manager implementions such as {@link KeyInfoGeneratorManager}. + * + * @return the specifc type of credential handled by the generators produced by this factory + */ + public Class getCredentialType(); + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/security/keyinfo/KeyInfoGeneratorManager.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/security/keyinfo/KeyInfoGeneratorManager.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/security/keyinfo/KeyInfoGeneratorManager.java 17 Aug 2012 15:17:13 -0000 1.1 @@ -0,0 +1,80 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.security.keyinfo; + +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import org.opensaml.xml.security.credential.Credential; + +/** + * A manager for {@link KeyInfoGeneratorFactory} instances. Factories are uniquely indexed according to the + * value returned by {@link KeyInfoGeneratorFactory#getCredentialType()}. + */ +public class KeyInfoGeneratorManager { + + /** The factories being managed, indexed by credential type. */ + private Map, KeyInfoGeneratorFactory> factories; + + /** Constructor. */ + public KeyInfoGeneratorManager() { + factories = new HashMap, KeyInfoGeneratorFactory>(5); + } + + /** + * Register a factory within this manager instance. If a factory already exists + * for that credential type, it will be replaced. + * + * @param factory the factory to register + */ + public void registerFactory(KeyInfoGeneratorFactory factory) { + factories.put(factory.getCredentialType(), factory); + } + + /** + * De-register a factory within this manager instance. + * + * @param factory the factory to de-register + */ + public void deregisterFactory(KeyInfoGeneratorFactory factory) { + factories.remove(factory.getCredentialType()); + } + + /** + * Get the (unmodifiable) collection of all factories managed by this manager. + * + * @return the collection of managed factories + */ + public Collection getFactories() { + return Collections.unmodifiableCollection(factories.values()); + } + + /** + * Get the factory which produces KeyInfoGenerators which can handle + * the specified credential. + * + * @param credential the credential for which to locate a factory + * @return a KeyInfoGeneratorFactory instance appropriate for the credential + */ + public KeyInfoGeneratorFactory getFactory(Credential credential) { + return factories.get(credential.getCredentialType()); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/security/keyinfo/KeyInfoHelper.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/security/keyinfo/KeyInfoHelper.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/security/keyinfo/KeyInfoHelper.java 17 Aug 2012 15:17:13 -0000 1.1 @@ -0,0 +1,708 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.security.keyinfo; + +import java.math.BigInteger; +import java.security.KeyException; +import java.security.KeyFactory; +import java.security.NoSuchAlgorithmException; +import java.security.PublicKey; +import java.security.cert.CRLException; +import java.security.cert.CertificateEncodingException; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.X509CRL; +import java.security.cert.X509Certificate; +import java.security.interfaces.DSAParams; +import java.security.interfaces.DSAPublicKey; +import java.security.interfaces.RSAPublicKey; +import java.security.spec.DSAParameterSpec; +import java.security.spec.DSAPublicKeySpec; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.KeySpec; +import java.security.spec.RSAPublicKeySpec; +import java.util.Collection; +import java.util.LinkedList; +import java.util.List; + +import org.opensaml.xml.Configuration; +import org.opensaml.xml.XMLObjectBuilderFactory; +import org.opensaml.xml.security.x509.X509Util; +import org.opensaml.xml.signature.DSAKeyValue; +import org.opensaml.xml.signature.Exponent; +import org.opensaml.xml.signature.G; +import org.opensaml.xml.signature.KeyInfo; +import org.opensaml.xml.signature.KeyName; +import org.opensaml.xml.signature.KeyValue; +import org.opensaml.xml.signature.Modulus; +import org.opensaml.xml.signature.P; +import org.opensaml.xml.signature.Q; +import org.opensaml.xml.signature.RSAKeyValue; +import org.opensaml.xml.signature.X509Data; +import org.opensaml.xml.signature.X509IssuerName; +import org.opensaml.xml.signature.X509IssuerSerial; +import org.opensaml.xml.signature.X509SKI; +import org.opensaml.xml.signature.X509SerialNumber; +import org.opensaml.xml.signature.X509SubjectName; +import org.opensaml.xml.signature.Y; +import org.opensaml.xml.util.Base64; +import org.opensaml.xml.util.DatatypeHelper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Utility class for working with data inside a KeyInfo object. + * + * Methods are provided for converting the representation stored in the XMLTooling KeyInfo to Java + * java.security native types, and for storing these Java native types inside a KeyInfo. + */ +public class KeyInfoHelper { + + /** Factory for {@link java.security.cert.X509Certificate} and + * {@link java.security.cert.X509CRL} creation. */ + private static CertificateFactory x509CertFactory; + + /** Constructor. */ + protected KeyInfoHelper(){ + + } + + /** + * Get the set of key names inside the specified {@link KeyInfo} as a list of strings. + * + * @param keyInfo {@link KeyInfo} to retrieve key names from + * + * @return a list of key name strings + */ + public static List getKeyNames(KeyInfo keyInfo) { + List keynameList = new LinkedList(); + + if (keyInfo == null) { + return keynameList; + } + + List keyNames = keyInfo.getKeyNames(); + for (KeyName keyName : keyNames) { + if (keyName.getValue() != null) { + keynameList.add(keyName.getValue()); + } + } + + return keynameList; + } + + /** + * Add a new {@link KeyName} value to a KeyInfo. + * + * @param keyInfo the KeyInfo to which to add the new value + * @param keyNameValue the new key name value to add + */ + public static void addKeyName(KeyInfo keyInfo, String keyNameValue) { + KeyName keyName = (KeyName) Configuration.getBuilderFactory() + .getBuilder(KeyName.DEFAULT_ELEMENT_NAME) + .buildObject(KeyName.DEFAULT_ELEMENT_NAME); + keyName.setValue(keyNameValue); + keyInfo.getKeyNames().add(keyName); + } + + /** + * Get a list of the Java {@link java.security.cert.X509Certificate} within the given KeyInfo. + * + * @param keyInfo key info to extract the certificates from + * + * @return a list of Java {@link java.security.cert.X509Certificate}s + * + * @throws CertificateException thrown if there is a problem converting the + * X509 data into {@link java.security.cert.X509Certificate}s. + */ + public static List getCertificates(KeyInfo keyInfo) throws CertificateException { + List certList = new LinkedList(); + + if (keyInfo == null) { + return certList; + } + + List x509Datas = keyInfo.getX509Datas(); + for (X509Data x509Data : x509Datas) { + if (x509Data != null) { + certList.addAll(getCertificates(x509Data)); + } + } + + return certList; + } + + /** + * Get a list of the Java {@link java.security.cert.X509Certificate} within the given {@link X509Data}. + * + * @param x509Data {@link X509Data} from which to extract the certificate + * + * @return a list of Java {@link java.security.cert.X509Certificate}s + * + * @throws CertificateException thrown if there is a problem converting the + * X509 data into {@link java.security.cert.X509Certificate}s. + */ + public static List getCertificates(X509Data x509Data) throws CertificateException { + List certList = new LinkedList(); + + if (x509Data == null) { + return certList; + } + + for (org.opensaml.xml.signature.X509Certificate xmlCert : x509Data.getX509Certificates()) { + if (xmlCert != null && xmlCert.getValue() != null) { + X509Certificate newCert = getCertificate(xmlCert); + certList.add(newCert); + } + } + + return certList; + } + + /** + * Convert an {@link org.opensaml.xml.signature.X509Certificate} into a native Java representation. + * + * @param xmlCert an {@link org.opensaml.xml.signature.X509Certificate} + * + * @return a {@link java.security.cert.X509Certificate} + * + * @throws CertificateException thrown if there is a problem converting the + * X509 data into {@link java.security.cert.X509Certificate}s. + */ + public static X509Certificate getCertificate(org.opensaml.xml.signature.X509Certificate xmlCert) + throws CertificateException { + + if (xmlCert == null || xmlCert.getValue() == null) { + return null; + } + + Collection certs = X509Util.decodeCertificate(Base64.decode(xmlCert.getValue())); + if (certs != null && certs.iterator().hasNext()) { + return certs.iterator().next(); + } else { + return null; + } + } + + /** + * Get a list of the Java {@link java.security.cert.X509CRL}s within the given {@link KeyInfo}. + * + * @param keyInfo the {@link KeyInfo} to extract the CRL's from + * + * @return a list of Java {@link java.security.cert.X509CRL}s + * + * @throws CRLException thrown if there is a problem converting the + * CRL data into {@link java.security.cert.X509CRL}s + */ + public static List getCRLs(KeyInfo keyInfo) throws CRLException { + List crlList = new LinkedList(); + + if (keyInfo == null) { + return crlList; + } + + List x509Datas = keyInfo.getX509Datas(); + for (X509Data x509Data : x509Datas) { + if (x509Data != null) { + crlList.addAll(getCRLs(x509Data)); + } + } + + return crlList; + } + + /** + * Get a list of the Java {@link java.security.cert.X509CRL}s within the given {@link X509Data}. + * + * @param x509Data {@link X509Data} to extract the CRLs from + * + * @return a list of Java {@link java.security.cert.X509CRL}s + * + * @throws CRLException thrown if there is a problem converting the + * CRL data into {@link java.security.cert.X509CRL}s + */ + public static List getCRLs(X509Data x509Data) throws CRLException { + List crlList = new LinkedList(); + + if (x509Data == null) { + return crlList; + } + + for (org.opensaml.xml.signature.X509CRL xmlCRL : x509Data.getX509CRLs()) { + if (xmlCRL != null && xmlCRL.getValue() != null) { + X509CRL newCRL = getCRL(xmlCRL); + crlList.add(newCRL); + } + } + + return crlList; + } + + /** + * Convert an {@link org.opensaml.xml.signature.X509CRL} into a native Java representation. + * + * @param xmlCRL object to extract the CRL from + * + * @return a native Java {@link java.security.cert.X509CRL} object + * + * @throws CRLException thrown if there is a problem converting the + * CRL data into {@link java.security.cert.X509CRL}s + */ + public static X509CRL getCRL(org.opensaml.xml.signature.X509CRL xmlCRL) throws CRLException { + + if (xmlCRL == null || xmlCRL.getValue() == null) { + return null; + } + + Collection crls = X509Util.decodeCRLs(Base64.decode(xmlCRL.getValue())); + return crls.iterator().next(); + } + + /** + * Converts a native Java {@link java.security.cert.X509Certificate} into the corresponding + * XMLObject and stores it in a {@link KeyInfo} in the first {@link X509Data} element. + * The X509Data element will be created if necessary. + * + * @param keyInfo the {@link KeyInfo} object into which to add the certificate + * @param cert the Java {@link java.security.cert.X509Certificate} to add + * @throws CertificateEncodingException thrown when there is an error converting the Java + * certificate representation to the XMLObject representation + */ + public static void addCertificate(KeyInfo keyInfo, X509Certificate cert) throws CertificateEncodingException { + X509Data x509Data; + if (keyInfo.getX509Datas().size() == 0) { + x509Data = (X509Data) Configuration.getBuilderFactory() + .getBuilder(X509Data.DEFAULT_ELEMENT_NAME) + .buildObject(X509Data.DEFAULT_ELEMENT_NAME); + keyInfo.getX509Datas().add(x509Data); + } else { + x509Data = keyInfo.getX509Datas().get(0); + } + x509Data.getX509Certificates().add(buildX509Certificate(cert)); + } + + /** + * Converts a native Java {@link java.security.cert.X509CRL} into the corresponding XMLObject and stores it + * in a {@link KeyInfo} in the first {@link X509Data} element. The X509Data element + * will be created if necessary. + * + * @param keyInfo the {@link KeyInfo} object into which to add the CRL + * @param crl the Java {@link java.security.cert.X509CRL} to add + * @throws CRLException thrown when there is an error converting the Java + * CRL representation to the XMLObject representation + */ + public static void addCRL(KeyInfo keyInfo, X509CRL crl) throws CRLException { + X509Data x509Data; + if (keyInfo.getX509Datas().size() == 0) { + x509Data = (X509Data) Configuration.getBuilderFactory() + .getBuilder(X509Data.DEFAULT_ELEMENT_NAME) + .buildObject(X509Data.DEFAULT_ELEMENT_NAME); + keyInfo.getX509Datas().add(x509Data); + } else { + x509Data = keyInfo.getX509Datas().get(0); + } + x509Data.getX509CRLs().add(buildX509CRL(crl)); + } + + /** + * Builds an {@link org.opensaml.xml.signature.X509Certificate} XMLObject from a native + * Java {@link java.security.cert.X509Certificate}. + * + * @param cert the Java {@link java.security.cert.X509Certificate} to convert + * @return a {@link org.opensaml.xml.signature.X509Certificate} XMLObject + * @throws CertificateEncodingException thrown when there is an error converting the Java + * certificate representation to the XMLObject representation + */ + public static org.opensaml.xml.signature.X509Certificate + buildX509Certificate(X509Certificate cert) throws CertificateEncodingException { + org.opensaml.xml.signature.X509Certificate xmlCert = + (org.opensaml.xml.signature.X509Certificate) Configuration.getBuilderFactory() + .getBuilder(org.opensaml.xml.signature.X509Certificate.DEFAULT_ELEMENT_NAME) + .buildObject(org.opensaml.xml.signature.X509Certificate.DEFAULT_ELEMENT_NAME); + + xmlCert.setValue(Base64.encodeBytes(cert.getEncoded())); + + return xmlCert; + } + + /** + * Builds an {@link org.opensaml.xml.signature.X509CRL} XMLObject from + * a native Java {@link java.security.cert.X509CRL}. + * + * @param crl the Java {@link java.security.cert.X509CRL} to convert + * @return a {@link org.opensaml.xml.signature.X509CRL} XMLObject + * @throws CRLException thrown when there is an error converting the Java + * CRL representation to the XMLObject representation + */ + public static org.opensaml.xml.signature.X509CRL buildX509CRL(X509CRL crl) throws CRLException { + org.opensaml.xml.signature.X509CRL xmlCRL = + (org.opensaml.xml.signature.X509CRL) Configuration.getBuilderFactory() + .getBuilder(org.opensaml.xml.signature.X509CRL.DEFAULT_ELEMENT_NAME) + .buildObject(org.opensaml.xml.signature.X509CRL.DEFAULT_ELEMENT_NAME); + + xmlCRL.setValue(Base64.encodeBytes(crl.getEncoded())); + + return xmlCRL; + } + + /** + * Build an {@link X509SubjectName} containing a given subject name. + * + * @param subjectName the name content + * @return the new X509SubjectName + */ + public static X509SubjectName buildX509SubjectName(String subjectName) { + X509SubjectName xmlSubjectName = (X509SubjectName) Configuration.getBuilderFactory() + .getBuilder(X509SubjectName.DEFAULT_ELEMENT_NAME) + .buildObject(X509SubjectName.DEFAULT_ELEMENT_NAME); + xmlSubjectName.setValue(subjectName); + return xmlSubjectName; + } + + /** + * Build an {@link X509IssuerSerial} containing a given issuer name and serial number. + * + * @param issuerName the name content + * @param serialNumber the serial number content + * @return the new X509IssuerSerial + */ + public static X509IssuerSerial buildX509IssuerSerial(String issuerName, BigInteger serialNumber) { + X509IssuerName xmlIssuerName = (X509IssuerName) Configuration.getBuilderFactory() + .getBuilder(X509IssuerName.DEFAULT_ELEMENT_NAME) + .buildObject(X509IssuerName.DEFAULT_ELEMENT_NAME); + xmlIssuerName.setValue(issuerName); + + X509SerialNumber xmlSerialNumber = (X509SerialNumber) Configuration.getBuilderFactory() + .getBuilder(X509SerialNumber.DEFAULT_ELEMENT_NAME) + .buildObject(X509SerialNumber.DEFAULT_ELEMENT_NAME); + xmlSerialNumber.setValue(serialNumber); + + X509IssuerSerial xmlIssuerSerial = (X509IssuerSerial) Configuration.getBuilderFactory() + .getBuilder(X509IssuerSerial.DEFAULT_ELEMENT_NAME) + .buildObject(X509IssuerSerial.DEFAULT_ELEMENT_NAME); + xmlIssuerSerial.setX509IssuerName(xmlIssuerName); + xmlIssuerSerial.setX509SerialNumber(xmlSerialNumber); + + return xmlIssuerSerial; + } + + /** + * Build an {@link X509SKI} containing the subject key identifier extension value contained within + * a certificate. + * + * @param javaCert the Java X509Certificate from which to extract the subject key identifier value. + * @return a new X509SKI object, or null if the certificate did not contain the subject key identifier extension + */ + public static X509SKI buildX509SKI(X509Certificate javaCert) { + byte[] skiPlainValue = X509Util.getSubjectKeyIdentifier(javaCert); + if (skiPlainValue == null || skiPlainValue.length == 0) { + return null; + } + + X509SKI xmlSKI = (X509SKI) Configuration.getBuilderFactory() + .getBuilder(X509SKI.DEFAULT_ELEMENT_NAME) + .buildObject(X509SKI.DEFAULT_ELEMENT_NAME); + xmlSKI.setValue(Base64.encodeBytes(skiPlainValue)); + + return xmlSKI; + } + + /** + * Converts a Java DSA or RSA public key into the corresponding XMLObject and stores it + * in a {@link KeyInfo} in a new {@link KeyValue} element. + * + * As input, only supports {@link PublicKey}s which are instances of either + * {@link java.security.interfaces.DSAPublicKey} or + * {@link java.security.interfaces.RSAPublicKey} + * + * @param keyInfo the {@link KeyInfo} element to which to add the key + * @param pk the native Java {@link PublicKey} to add + * @throws IllegalArgumentException thrown if an unsupported public key + * type is passed + */ + public static void addPublicKey(KeyInfo keyInfo, PublicKey pk) throws IllegalArgumentException { + KeyValue keyValue = (KeyValue) Configuration.getBuilderFactory() + .getBuilder(KeyValue.DEFAULT_ELEMENT_NAME) + .buildObject(KeyValue.DEFAULT_ELEMENT_NAME); + + if (pk instanceof RSAPublicKey) { + keyValue.setRSAKeyValue(buildRSAKeyValue((RSAPublicKey) pk)); + } else if (pk instanceof DSAPublicKey) { + keyValue.setDSAKeyValue(buildDSAKeyValue((DSAPublicKey) pk)); + } else { + throw new IllegalArgumentException("Only RSAPublicKey and DSAPublicKey are supported"); + } + + keyInfo.getKeyValues().add(keyValue); + } + + /** + * Builds an {@link RSAKeyValue} XMLObject from the Java security RSA public key type. + * + * @param rsaPubKey a native Java {@link RSAPublicKey} + * @return an {@link RSAKeyValue} XMLObject + */ + public static RSAKeyValue buildRSAKeyValue(RSAPublicKey rsaPubKey) { + XMLObjectBuilderFactory builderFactory = Configuration.getBuilderFactory(); + RSAKeyValue rsaKeyValue = (RSAKeyValue) builderFactory + .getBuilder(RSAKeyValue.DEFAULT_ELEMENT_NAME) + .buildObject(RSAKeyValue.DEFAULT_ELEMENT_NAME); + Modulus modulus = (Modulus) builderFactory + .getBuilder(Modulus.DEFAULT_ELEMENT_NAME) + .buildObject(Modulus.DEFAULT_ELEMENT_NAME); + Exponent exponent = (Exponent) builderFactory + .getBuilder(Exponent.DEFAULT_ELEMENT_NAME) + .buildObject(Exponent.DEFAULT_ELEMENT_NAME); + + modulus.setValueBigInt(rsaPubKey.getModulus()); + rsaKeyValue.setModulus(modulus); + + exponent.setValueBigInt(rsaPubKey.getPublicExponent()); + rsaKeyValue.setExponent(exponent); + + return rsaKeyValue; + } + + /** + * Builds a {@link DSAKeyValue} XMLObject from the Java security DSA public key type. + * + * @param dsaPubKey a native Java {@link DSAPublicKey} + * @return an {@link DSAKeyValue} XMLObject + */ + public static DSAKeyValue buildDSAKeyValue(DSAPublicKey dsaPubKey) { + XMLObjectBuilderFactory builderFactory = Configuration.getBuilderFactory(); + DSAKeyValue dsaKeyValue = (DSAKeyValue) builderFactory + .getBuilder(DSAKeyValue.DEFAULT_ELEMENT_NAME) + .buildObject(DSAKeyValue.DEFAULT_ELEMENT_NAME); + Y y = (Y) builderFactory.getBuilder(Y.DEFAULT_ELEMENT_NAME).buildObject(Y.DEFAULT_ELEMENT_NAME); + G g = (G) builderFactory.getBuilder(G.DEFAULT_ELEMENT_NAME).buildObject(G.DEFAULT_ELEMENT_NAME); + P p = (P) builderFactory.getBuilder(P.DEFAULT_ELEMENT_NAME).buildObject(P.DEFAULT_ELEMENT_NAME); + Q q = (Q) builderFactory.getBuilder(Q.DEFAULT_ELEMENT_NAME).buildObject(Q.DEFAULT_ELEMENT_NAME); + + y.setValueBigInt(dsaPubKey.getY()); + dsaKeyValue.setY(y); + + g.setValueBigInt(dsaPubKey.getParams().getG()); + dsaKeyValue.setG(g); + + p.setValueBigInt(dsaPubKey.getParams().getP()); + dsaKeyValue.setP(p); + + q.setValueBigInt(dsaPubKey.getParams().getQ()); + dsaKeyValue.setQ(q); + + return dsaKeyValue; + } + + + /** + * Extracts all the public keys within the given {@link KeyInfo}'s {@link KeyValue}s. This method only + * supports DSA and RSA key types. + * + * @param keyInfo {@link KeyInfo} to extract the keys out of + * + * @return a list of native Java {@link PublicKey} objects + * + * @throws KeyException thrown if the given key data can not be converted into {@link PublicKey} + */ + public static List getPublicKeys(KeyInfo keyInfo) throws KeyException{ + List keys = new LinkedList(); + + if (keyInfo == null || keyInfo.getKeyValues() == null) { + return keys; + } + + for(KeyValue keyDescriptor : keyInfo.getKeyValues()){ + keys.add(getKey(keyDescriptor)); + } + + return keys; + } + + /** + * Extracts the DSA or RSA public key within the {@link KeyValue}. + * + * @param keyValue the {@link KeyValue} to extract the key from + * + * @return a native Java security {@link java.security.Key} object + * + * @throws KeyException thrown if the given key data can not be converted into {@link PublicKey} + */ + public static PublicKey getKey(KeyValue keyValue) throws KeyException{ + if(keyValue.getDSAKeyValue() != null){ + return getDSAKey(keyValue.getDSAKeyValue()); + }else if(keyValue.getRSAKeyValue() != null){ + return getRSAKey(keyValue.getRSAKeyValue()); + }else{ + return null; + } + } + + /** + * Builds an DSA key from a {@link DSAKeyValue} element. The element must contain values + * for all required DSA public key parameters, including values for shared key family + * values P, Q and G. + * + * @param keyDescriptor the {@link DSAKeyValue} key descriptor + * + * @return a new {@link DSAPublicKey} instance of {@link PublicKey} + * + * @throws KeyException thrown if the key algorithm is not supported by the JCE or the key spec does not + * contain valid information + */ + public static PublicKey getDSAKey(DSAKeyValue keyDescriptor) throws KeyException { + if (! hasCompleteDSAParams(keyDescriptor)) { + throw new KeyException("DSAKeyValue element did not contain at least one of DSA parameters P, Q or G"); + } + + BigInteger gComponent = keyDescriptor.getG().getValueBigInt(); + BigInteger pComponent = keyDescriptor.getP().getValueBigInt(); + BigInteger qComponent = keyDescriptor.getQ().getValueBigInt(); + + DSAParams dsaParams = new DSAParameterSpec(pComponent, qComponent, gComponent); + return getDSAKey(keyDescriptor, dsaParams); + } + + /** + * Builds a DSA key from an {@link DSAKeyValue} element and the supplied Java {@link DSAParams}, + * which supplies key material from a shared key family. + * + * @param keyDescriptor the {@link DSAKeyValue} key descriptor + * @param dsaParams the {@link DSAParams} DSA key family parameters + * + * @return a new {@link DSAPublicKey} instance of {@link PublicKey} + * + * @throws KeyException thrown if the key algorithm is not supported by the JCE or the key spec does not + * contain valid information + */ + public static PublicKey getDSAKey(DSAKeyValue keyDescriptor, DSAParams dsaParams) throws KeyException { + BigInteger yComponent = keyDescriptor.getY().getValueBigInt(); + + DSAPublicKeySpec keySpec = + new DSAPublicKeySpec(yComponent, dsaParams.getP(), dsaParams.getQ(), dsaParams.getG()); + return buildKey(keySpec, "DSA"); + } + + /** + * Check whether the specified {@link DSAKeyValue} element has the all optional DSA + * values which can be shared amongst many keys in a DSA "key family", and + * are presumed to be known from context. + * + * @param keyDescriptor the {@link DSAKeyValue} element to check + * @return true if all parameters are present and non-empty, false otherwise + */ + public static boolean hasCompleteDSAParams(DSAKeyValue keyDescriptor) { + if ( keyDescriptor.getG() == null || DatatypeHelper.isEmpty(keyDescriptor.getG().getValue()) + || keyDescriptor.getP() == null || DatatypeHelper.isEmpty(keyDescriptor.getP().getValue()) + || keyDescriptor.getQ() == null || DatatypeHelper.isEmpty(keyDescriptor.getQ().getValue()) + ) { + return false; + } + return true; + } + + /** + * Builds an RSA key from an {@link RSAKeyValue} element. + * + * @param keyDescriptor the {@link RSAKeyValue} key descriptor + * + * @return a new {@link RSAPublicKey} instance of {@link PublicKey} + * + * @throws KeyException thrown if the key algorithm is not supported by the JCE or the key spec does not + * contain valid information + */ + public static PublicKey getRSAKey(RSAKeyValue keyDescriptor) throws KeyException { + BigInteger modulus = keyDescriptor.getModulus().getValueBigInt(); + BigInteger exponent = keyDescriptor.getExponent().getValueBigInt(); + + RSAPublicKeySpec keySpec = new RSAPublicKeySpec(modulus, exponent); + return buildKey(keySpec, "RSA"); + } + + /** + * Decode a base64-encoded ds:CryptoBinary value to a native Java BigInteger type. + * + * @param base64Value base64-encoded CryptoBinary value + * @return the decoded BigInteger + */ + public static final BigInteger decodeBigIntegerFromCryptoBinary(String base64Value) { + return new BigInteger(1, Base64.decode(base64Value)); + } + + /** + * Encode a native Java BigInteger type to a base64-encoded ds:CryptoBinary value. + * + * @param bigInt the BigInteger value + * @return the encoded CryptoBinary value + */ + public static final String encodeCryptoBinaryFromBigInteger(BigInteger bigInt) { + // This code is really complicated, for now just use the Apache xmlsec lib code directly. + byte[] bigIntBytes = org.apache.xml.security.utils.Base64.encode(bigInt, bigInt.bitLength()); + return Base64.encodeBytes(bigIntBytes); + } + + /** + * Generates a public key from the given key spec. + * + * @param keySpec {@link KeySpec} specification for the key + * @param keyAlgorithm key generation algorithm, only DSA and RSA supported + * + * @return the generated {@link PublicKey} + * + * @throws KeyException thrown if the key algorithm is not supported by the JCE or the key spec does not + * contain valid information + */ + protected static PublicKey buildKey(KeySpec keySpec, String keyAlgorithm) throws KeyException { + Logger log = getLogger(); + try { + KeyFactory keyFactory = KeyFactory.getInstance(keyAlgorithm); + return keyFactory.generatePublic(keySpec); + } catch (NoSuchAlgorithmException e) { + log.error(keyAlgorithm + " algorithm is not supported by this VM", e); + throw new KeyException(keyAlgorithm + "algorithm is not supported by the JCE", e); + } catch (InvalidKeySpecException e) { + log.error("Invalid key information", e); + throw new KeyException("Invalid key information", e); + } + } + + /** + * Get the Java certificate factory singleton. + * + * @return {@link CertificateFactory} the factory used to create X509 certificate objects + * + * @throws CertificateException thrown if the factory can not be created + */ + protected static CertificateFactory getX509CertFactory() throws CertificateException { + + if (x509CertFactory == null) { + x509CertFactory = CertificateFactory.getInstance("X.509"); + } + + return x509CertFactory; + } + + /** + * Get an SLF4J Logger. + * + * @return a Logger instance + */ + private static Logger getLogger() { + return LoggerFactory.getLogger(KeyInfoHelper.class); + } +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/security/keyinfo/KeyInfoProvider.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/security/keyinfo/KeyInfoProvider.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/security/keyinfo/KeyInfoProvider.java 17 Aug 2012 15:17:13 -0000 1.1 @@ -0,0 +1,63 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.security.keyinfo; + +import java.util.Collection; + +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.security.CriteriaSet; +import org.opensaml.xml.security.SecurityException; +import org.opensaml.xml.security.credential.Credential; +import org.opensaml.xml.signature.KeyInfo; + +/** + * Interface for providers used in conjunction with a {@link KeyInfoCredentialResolver} which + * support resolving {@link Credential}s based on a child element of {@link KeyInfo}. + */ +public interface KeyInfoProvider { + + /** + * Process a specified KeyInfo child (XMLobject) and attempt to resolve a credential from it. + * + * @param resolver reference to a resolver which is calling the provider + * @param keyInfoChild the KeyInfo child being processed + * @param criteriaSet the credential criteria the credential must satisfy + * @param kiContext the resolution context, used for sharing state amongst resolvers and providers + * + * @return a resolved Credential collection, or null + * + * @throws SecurityException if there is an error during credential resolution. + * Note: failure to resolve a credential is not an error. + */ + public Collection process(KeyInfoCredentialResolver resolver, XMLObject keyInfoChild, + CriteriaSet criteriaSet, KeyInfoResolutionContext kiContext) throws SecurityException; + + /** + * Evaluate whether the given provider should attempt to handle resolving a credential + * from the specified KeyInfo child. + * + * An evaluation of true does not guarantee that a credential can or will be + * extracted form the particular KeyInfo child, only that processing should be attempted. + * + * @param keyInfoChild the KeyInfo child object to consider + * + * @return true if the provider should attempt to resolve credentials, false otherwise + */ + public boolean handles(XMLObject keyInfoChild); + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/security/keyinfo/KeyInfoResolutionContext.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/security/keyinfo/KeyInfoResolutionContext.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/security/keyinfo/KeyInfoResolutionContext.java 17 Aug 2012 15:17:13 -0000 1.1 @@ -0,0 +1,147 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.security.keyinfo; + +import java.security.Key; +import java.util.Collection; +import java.util.Collections; +import java.util.Map; +import java.util.Set; + +import org.opensaml.xml.security.credential.Credential; +import org.opensaml.xml.signature.KeyInfo; +import org.opensaml.xml.util.LazyMap; +import org.opensaml.xml.util.LazySet; + + +/** + * Resolution context class that is used to supply state information to, and to share information + * amongst, {@link KeyInfoProvider}s. + * + *

+ * The extensible properties map available from {@link #getProperties()} may for example used to communicate + * state between two or more providers, or between a provider and custom logic in a particular implementation + * of {@link KeyInfoCredentialResolver}. It is recommended that providers and/or resolvers define + * and use property names in such a way as to avoid collisions with those used by other providers and resolvers, + * and to also clearly define the data type stored for each propery name. + *

+ * + */ +public class KeyInfoResolutionContext { + + /** The KeyInfo being processed. */ + private KeyInfo keyInfo; + + /** Key names which are known to be associated with the KeyInfo being processed. + * These may have for example been extracted from KeyName elements present, + * or may have been inferred from the context in which the KeyInfo exists or + * is being used. */ + private Set keyNames; + + /** Get the key currently known to be represented by the KeyInfo. */ + private Key key; + + /** This list provides KeyInfo resolvers and providers in a particular processing + * environment access to credentials that may have already been previously resolved. */ + private Collection resolvedCredentials; + + /** Extensible map of properties used to share state amongst providers and/or resolver logic. */ + private final Map properties; + + /** + * Constructor. + * + * @param credentials a reference to the collection in which credentials previously + * resolved in a processing flow are being stored + */ + public KeyInfoResolutionContext(Collection credentials) { + resolvedCredentials = Collections.unmodifiableCollection(credentials); + properties = new LazyMap(); + keyNames = new LazySet(); + } + + /** + * Gets the KeyInfo being processed. + * + * @return Returns the keyInfo. + */ + public KeyInfo getKeyInfo() { + return keyInfo; + } + + /** + * Sets the KeyInfo being processed. + * + * @param newKeyInfo The keyInfo to set. + */ + public void setKeyInfo(KeyInfo newKeyInfo) { + keyInfo = newKeyInfo; + } + + /** + * The key names which are currently known. + * + * These key names should be those which are known to be associated with the + * key represented by the KeyInfo being processed. These may have for example + * been directly extracted from KeyName elements present, or may have been + * inferred from the context in which the KeyInfo exists or is being used. + * + * @return the set of key names + * + * */ + public Set getKeyNames() { + return keyNames; + } + + /** + * Get the key currently known to be represented by the KeyInfo. + * + * @return the key currently known to be represented by the KeyInfo + * or null if not currently known + */ + public Key getKey() { + return key; + } + + /** + * Set the key currently known to be represented by the KeyInfo. + * + * @param newKey the new Key + */ + public void setKey(Key newKey) { + key = newKey; + } + + /** + * Get the set of credentials previously resolved. + * + * @return Returns the keyValueCredential. + */ + public Collection getResolvedCredentials() { + return resolvedCredentials; + } + + /** + * Get the extensible properties map. + * + * @return Returns the properties. + */ + public Map getProperties() { + return properties; + } +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/security/keyinfo/LocalKeyInfoCredentialResolver.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/security/keyinfo/LocalKeyInfoCredentialResolver.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/security/keyinfo/LocalKeyInfoCredentialResolver.java 17 Aug 2012 15:17:13 -0000 1.1 @@ -0,0 +1,179 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.security.keyinfo; + +import java.security.PublicKey; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import org.opensaml.xml.encryption.Decrypter; +import org.opensaml.xml.security.CriteriaSet; +import org.opensaml.xml.security.SecurityException; +import org.opensaml.xml.security.credential.Credential; +import org.opensaml.xml.security.credential.CredentialResolver; +import org.opensaml.xml.security.criteria.KeyNameCriteria; +import org.opensaml.xml.security.criteria.PublicKeyCriteria; +import org.opensaml.xml.signature.KeyInfo; + +/** + * A simple specialization of {@link BasicProviderKeyInfoCredentialResolver} + * which is capable of using information from a {@link KeyInfo} to resolve + * local credentials from a supplied {@link CredentialResolver} which manages local credentials. + * + *

+ * The local credential resolver supplied should manage and return credentials + * which contain either a secret (symmetric) key or the private key half of a + * key pair. + *

+ * + *

+ * A typical use case for this class would be as a resolver of decryption keys, + * such as is needed by {@link Decrypter}. + *

+ * + *

+ * Resolution proceeds as follows: + *

    + *
  1. Any credential resolved via the standard {@link BasicProviderKeyInfoCredentialResolver} + * resolution process which is not a local credential will be removed + * from the effective set of credentials to be returned. Note that a configured + * {@link KeyInfoProvider} may have itself already resolved local credentials using a + * different mechanism. These will not be removed.
  2. + *
  3. If a credential so removed contained a public key, that key will be used as a + * resolution criteria input to the local credential resolver. Any local credentials + * so resolved will be added to the set to be returned.
  4. + *
  5. Similarly, any key names from {@link KeyInfoResolutionContext#getKeyNames()} will also + * be used as resolution criteria for local credentials and the resultant credentials + * added to the set to be returned.
  6. + *
+ *

+ */ +public class LocalKeyInfoCredentialResolver extends BasicProviderKeyInfoCredentialResolver { + + /** The resovler which is used to resolve local credentials. */ + private CredentialResolver localCredResolver; + + /** + * Constructor. + * + * @param keyInfoProviders the list of KeyInfoProvider's to use in this resolver + * @param localCredentialResolver resolver of local credentials + */ + public LocalKeyInfoCredentialResolver(List keyInfoProviders, + CredentialResolver localCredentialResolver) { + super(keyInfoProviders); + + if (localCredentialResolver == null) { + throw new IllegalArgumentException("Local credential resolver must be supplied"); + } + + localCredResolver = localCredentialResolver; + } + + /** + * Get the resolver for local credentials. + * + * The credentials managed and returned by this resolver should all contain + * either a secret (symmetric) or private key. + * + * @return resolver of local credentials + */ + public CredentialResolver getLocalCredentialResolver() { + return localCredResolver; + } + + /** {@inheritDoc} */ + protected void postProcess(KeyInfoResolutionContext kiContext, CriteriaSet criteriaSet, + List credentials) throws SecurityException { + + ArrayList localCreds = new ArrayList(); + + for (Credential cred : credentials) { + if (isLocalCredential(cred)) { + localCreds.add(cred); + } else if (cred.getPublicKey() != null) { + localCreds.addAll(resolveByPublicKey(cred.getPublicKey())); + } + } + + // Also resolve local creds based on any key names that are known + for (String keyName : kiContext.getKeyNames()) { + localCreds.addAll(resolveByKeyName(keyName)); + } + + credentials.clear(); + credentials.addAll(localCreds); + } + + /** + * Determine whether the credential is a local credential. + * + * A local credential will have either a private key or a secret (symmetric) key. + * + * @param credential the credential to evaluate + * @return true if the credential has either a private or secret key, false otherwise + */ + protected boolean isLocalCredential(Credential credential) { + return credential.getPrivateKey() != null || credential.getSecretKey() != null; + } + + /** + * Resolve credentials from local resolver using key name criteria. + * + * @param keyName the key name criteria + * @return collection of local credentials identified by the specified key name + * @throws SecurityException thrown if there is a problem resolving credentials from the + * local credential resolver + */ + protected Collection resolveByKeyName(String keyName) throws SecurityException { + ArrayList localCreds = new ArrayList(); + + CriteriaSet criteriaSet = new CriteriaSet( new KeyNameCriteria(keyName) ); + for (Credential cred : getLocalCredentialResolver().resolve(criteriaSet)) { + if (isLocalCredential(cred)) { + localCreds.add(cred); + } + } + + return localCreds; + } + + /** + * Resolve credentials from local resolver using public key criteria. + * + * @param publicKey the public key criteria + * @return collection of local credentials which contain the private key + * corresponding to the specified public key + * @throws SecurityException thrown if there is a problem resolving credentials from the + * local credential resolver + */ + protected Collection resolveByPublicKey(PublicKey publicKey) throws SecurityException { + ArrayList localCreds = new ArrayList(); + + CriteriaSet criteriaSet = new CriteriaSet( new PublicKeyCriteria(publicKey) ); + for (Credential cred : getLocalCredentialResolver().resolve(criteriaSet)) { + if (isLocalCredential(cred)) { + localCreds.add(cred); + } + } + + return localCreds; + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/security/keyinfo/NamedKeyInfoGeneratorManager.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/security/keyinfo/NamedKeyInfoGeneratorManager.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/security/keyinfo/NamedKeyInfoGeneratorManager.java 17 Aug 2012 15:17:13 -0000 1.1 @@ -0,0 +1,169 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.security.keyinfo; + +import java.util.Collections; +import java.util.Map; +import java.util.Set; + +import org.opensaml.xml.security.credential.Credential; +import org.opensaml.xml.util.LazyMap; + +/** + * A manager for named sets of {@link KeyInfoGeneratorFactory} instances. Each name key serves as an index to an + * instance of {@link KeyInfoGeneratorManager}. + */ +public class NamedKeyInfoGeneratorManager { + + /** The set of named factory managers. */ + private Map managers; + + /** The default manager for unnamed factories. */ + private KeyInfoGeneratorManager defaultManager; + + /** Flag indicating whether the default (unnamed) factory manager will be used to + * lookup factories for credentials. */ + private boolean useDefaultManager; + + /** Constructor. */ + public NamedKeyInfoGeneratorManager() { + managers = new LazyMap(); + defaultManager = new KeyInfoGeneratorManager(); + useDefaultManager = true; + } + + /** + * Set the option as to whether the default (unnamed) manager will be used to lookup factories + * for credentials if there is no appropriate named factory for the credential type. + * + * @param newValue the new option value + */ + public void setUseDefaultManager(boolean newValue) { + useDefaultManager = newValue; + } + + /** + * Get the (unmodifiable) set of names of factory managers currently available. + * + * @return the set of all manager names currently configured + */ + public Set getManagerNames() { + return Collections.unmodifiableSet(managers.keySet()); + } + + /** + * Get the named factory manager. If it doesn't exist yet, one will be created. + * + * @param name the name of the manager to obtain + * @return the named manager + */ + public KeyInfoGeneratorManager getManager(String name) { + KeyInfoGeneratorManager manager = managers.get(name); + if (manager == null) { + manager = new KeyInfoGeneratorManager(); + managers.put(name, manager); + } + return manager; + } + + /** + * Remove the named factory manager, and all its managed factories. + * + * @param name the name of the manager to remove + */ + public void removeManager(String name) { + managers.remove(name); + } + + /** + * Register a factory within the specified named manager. If that + * named manager does not currently exist, it will be created. + * + * @param name the name of the factory manager + * @param factory the factory to register + */ + public void registerFactory(String name, KeyInfoGeneratorFactory factory) { + KeyInfoGeneratorManager manager = getManager(name); + manager.registerFactory(factory); + } + + /** + * De-register a factory within the specified named manager. + * + * @param name the name of the factory manager + * @param factory the factory to de-register + */ + public void deregisterFactory(String name, KeyInfoGeneratorFactory factory) { + KeyInfoGeneratorManager manager = managers.get(name); + if (manager == null) { + throw new IllegalArgumentException("Manager with name '" + name + "' does not exist"); + } + + manager.deregisterFactory(factory); + } + + /** + * Register a factory with the default (unnamed) manager. + * + * @param factory the factory to register + */ + public void registerDefaultFactory(KeyInfoGeneratorFactory factory) { + defaultManager.registerFactory(factory); + } + + /** + * De-register a factory with the default (unnamed) manager. + * + * @param factory the factory to de-register + */ + public void deregisterDefaultFactory(KeyInfoGeneratorFactory factory) { + defaultManager.deregisterFactory(factory); + } + + /** + * Get the default (unnamed) factory manager. + * + * @return the default factory manager + */ + public KeyInfoGeneratorManager getDefaultManager() { + return defaultManager; + } + + /** + * Lookup and return the named generator factory for the type of the credential specified. + * + * @param name the name of the factory manger + * @param credential the credential to evaluate + * @return a factory for generators appropriate for the specified credential + */ + public KeyInfoGeneratorFactory getFactory(String name, Credential credential) { + KeyInfoGeneratorManager manager = managers.get(name); + if (manager == null) { + throw new IllegalArgumentException("Manager with name '" + name + "' does not exist"); + } + + KeyInfoGeneratorFactory factory = manager.getFactory(credential); + if (factory == null) { + if (useDefaultManager) { + factory = defaultManager.getFactory(credential); + } + } + return factory; + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/security/keyinfo/StaticKeyInfoCredentialResolver.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/security/keyinfo/StaticKeyInfoCredentialResolver.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/security/keyinfo/StaticKeyInfoCredentialResolver.java 17 Aug 2012 15:17:13 -0000 1.1 @@ -0,0 +1,59 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.security.keyinfo; + +import java.util.List; + +import org.opensaml.xml.security.credential.Credential; +import org.opensaml.xml.security.credential.StaticCredentialResolver; + +/** + * Simple implementation of {@link KeyInfoCredentialResolver} which just stores and returns a static set of credentials. + * + *

+ * Note: no filtering or other evaluation of the credentials is performed. Any Criteria + * specified are ignored. For a similar Collection-based KeyInfoCredentialResolver implementation which does support + * evaluation and filtering based on supplied evaluable criteria, see {@link CollectionKeyInfoCredentialResolver}. + *

+ * + *

+ * This implementation might also be used at the end of a chain of KeyInfoCredentialResolvers in + * order to supply a default, fallback set of credentials, if none could otherwise be resolved. + *

+ */ +public class StaticKeyInfoCredentialResolver extends StaticCredentialResolver implements KeyInfoCredentialResolver { + + /** + * Constructor. + * + * @param credentials collection of credentials to be held by this resolver + */ + public StaticKeyInfoCredentialResolver(List credentials) { + super(credentials); + } + + /** + * Constructor. + * + * @param credential a single credential to be held by this resolver + */ + public StaticKeyInfoCredentialResolver(Credential credential) { + super(credential); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/security/keyinfo/StaticKeyInfoGenerator.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/security/keyinfo/StaticKeyInfoGenerator.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/security/keyinfo/StaticKeyInfoGenerator.java 17 Aug 2012 15:17:14 -0000 1.1 @@ -0,0 +1,167 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.security.keyinfo; + +import org.opensaml.xml.Configuration; +import org.opensaml.xml.io.Marshaller; +import org.opensaml.xml.io.MarshallingException; +import org.opensaml.xml.io.Unmarshaller; +import org.opensaml.xml.io.UnmarshallingException; +import org.opensaml.xml.security.SecurityException; +import org.opensaml.xml.security.credential.Credential; +import org.opensaml.xml.signature.KeyInfo; +import org.w3c.dom.Element; + +/** + * Implementation of {@link KeyInfoGenerator} which always returns static {@link KeyInfo} data. + * + * Note that the argument to {@link #generate(Credential)} is not used in generating the new KeyInfo, + * and so may be null. + * + * If the original KeyInfo that was passed to this instance is already the child of some other + * XMLObject at the time {@link #generate(Credential)} is called, then a newly constructed KeyInfo + * object will be returned that contains the same data as the original. Otherwise, the original + * KeyInfo instance is returned directly. + * + */ +public class StaticKeyInfoGenerator implements KeyInfoGenerator { + + /** The KeyInfo object held by this generator instance. */ + private KeyInfo keyInfo; + + /** Unmarshaller used in cloning operation. */ + private Unmarshaller keyInfoUnmarshaller; + + /** Marshaller used in cloning operation. */ + private Marshaller keyInfoMarshaller; + + /** + * Constructor. + * + * @param newKeyInfo the KeyInfo used as the basis to return new KeyInfo objects from this generator + */ + public StaticKeyInfoGenerator(KeyInfo newKeyInfo) { + setKeyInfo(newKeyInfo); + } + + /** {@inheritDoc} */ + public KeyInfo generate(Credential credential) throws SecurityException { + if (keyInfo.getParent() == null) { + return keyInfo; + } else { + return clone(keyInfo); + } + } + + /** + * Get the static KeyInfo object held by this generator. + * + * @return the currently held KeyInfo object + */ + public KeyInfo getKeyInfo() { + return keyInfo; + } + + /** + * Set the static KeyInfo object held by this generator. + * + * @param newKeyInfo the new KeyInfo object + */ + public void setKeyInfo(KeyInfo newKeyInfo) { + if (newKeyInfo == null) { + throw new IllegalArgumentException("KeyInfo may not be null"); + } + keyInfo = newKeyInfo; + } + + /** + * Clone a KeyInfo and return the new object. + * + * @param origKeyInfo the KeyInfo object to clone + * @return a new KeyInfo object cloned from the original + * @throws SecurityException thrown in there are marshalling or unmarshalling errors during cloning + */ + private KeyInfo clone(KeyInfo origKeyInfo) throws SecurityException { + // A brute force approach to cloning: + // 1) marshall the original (if necessary) + // 2) unmarshall a new object around the cached or newly marshalled DOM. + // 3) ensure only one of them caches the DOM (original or marshalled) + Element origDOM = origKeyInfo.getDOM(); + if (origDOM == null) { + try { + getMarshaller().marshall(origKeyInfo); + } catch (MarshallingException e) { + throw new SecurityException("Error marshalling the original KeyInfo during cloning", e); + } + } + + KeyInfo newKeyInfo = null; + try { + newKeyInfo = (KeyInfo) getUnmarshaller().unmarshall(origKeyInfo.getDOM()); + } catch (UnmarshallingException e) { + throw new SecurityException("Error unmarshalling the new KeyInfo during cloning", e); + } + + // If the original had no cached DOM, go ahead and drop so this operation doesn't have any side effects. + // If it did have, then drop it on the new one, so isn't cached by two objects. + if (origDOM == null) { + origKeyInfo.releaseChildrenDOM(true); + origKeyInfo.releaseDOM(); + } else { + newKeyInfo.releaseChildrenDOM(true); + newKeyInfo.releaseDOM(); + } + + return newKeyInfo; + } + + /** + * Get a KeyInfo marshaller. + * + * @return a KeyInfo marshaller + * @throws SecurityException thrown if there is an error obtaining the marshaller from the configuration + */ + private Marshaller getMarshaller() throws SecurityException { + if (keyInfoMarshaller != null) { + return keyInfoMarshaller; + } + keyInfoMarshaller = Configuration.getMarshallerFactory().getMarshaller(KeyInfo.DEFAULT_ELEMENT_NAME); + if (keyInfoMarshaller == null) { + throw new SecurityException("Could not obtain KeyInfo marshaller from the configuration"); + } + return keyInfoMarshaller; + } + + /** + * Get a KeyInfo unmarshaller. + * + * @return a KeyInfo unmarshaller + * @throws SecurityException thrown if there is an error obtaining the unmarshaller from the configuration + */ + private Unmarshaller getUnmarshaller() throws SecurityException { + if (keyInfoUnmarshaller != null) { + return keyInfoUnmarshaller; + } + keyInfoUnmarshaller = Configuration.getUnmarshallerFactory().getUnmarshaller(KeyInfo.DEFAULT_ELEMENT_NAME); + if (keyInfoUnmarshaller == null) { + throw new SecurityException("Could not obtain KeyInfo unmarshaller from the configuration"); + } + return keyInfoUnmarshaller; + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/security/keyinfo/package.html =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/security/keyinfo/package.html,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/security/keyinfo/package.html 17 Aug 2012 15:17:13 -0000 1.1 @@ -0,0 +1,6 @@ + + +Interfaces and classes for working with XML KeyInfo elements. These classes are generally used to +extract or resolve credential information. + + \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/security/keyinfo/provider/AbstractKeyInfoProvider.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/security/keyinfo/provider/AbstractKeyInfoProvider.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/security/keyinfo/provider/AbstractKeyInfoProvider.java 17 Aug 2012 15:17:18 -0000 1.1 @@ -0,0 +1,75 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.security.keyinfo.provider; + +import java.security.Key; + +import org.opensaml.xml.security.credential.Credential; +import org.opensaml.xml.security.keyinfo.KeyInfoCredentialContext; +import org.opensaml.xml.security.keyinfo.KeyInfoProvider; +import org.opensaml.xml.security.keyinfo.KeyInfoResolutionContext; + +/** + * Abstract super class for {@link KeyInfoProvider} implementations. + */ +public abstract class AbstractKeyInfoProvider implements KeyInfoProvider { + + /** + * Utility method to extract any key that might be present in the specified Credential. + * + * @param cred the Credential to evaluate + * @return the Key contained in the credential, or null if it does not contain a key. + */ + protected Key extractKeyValue(Credential cred) { + if (cred == null) { + return null; + } + if (cred.getPublicKey() != null) { + return cred.getPublicKey(); + } + // This could happen if key is derived, e.g. key agreement, etc + if (cred.getSecretKey() != null) { + return cred.getSecretKey(); + } + // Perhaps unlikely, but go ahead and check + if (cred.getPrivateKey() != null) { + return cred.getPrivateKey(); + } + return null; + } + + /** + * Build a credential context based on the current KeyInfo context, for return + * in a resolved credential. + * + * @param kiContext the current KeyInfo resolution context + * + * @return a new KeyInfo credential context + */ + protected KeyInfoCredentialContext buildCredentialContext(KeyInfoResolutionContext kiContext) { + // Simple for now, might do other stuff later. + // Just want to provide a single place to build credential contexts for + // a provider. + if (kiContext != null) { + return new KeyInfoCredentialContext(kiContext.getKeyInfo()); + } else { + return null; + } + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/security/keyinfo/provider/DSAKeyValueProvider.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/security/keyinfo/provider/DSAKeyValueProvider.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/security/keyinfo/provider/DSAKeyValueProvider.java 17 Aug 2012 15:17:18 -0000 1.1 @@ -0,0 +1,116 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.security.keyinfo.provider; + +import java.security.KeyException; +import java.security.PublicKey; +import java.util.Collection; + +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.security.CriteriaSet; +import org.opensaml.xml.security.SecurityException; +import org.opensaml.xml.security.credential.BasicCredential; +import org.opensaml.xml.security.credential.Credential; +import org.opensaml.xml.security.credential.CredentialContext; +import org.opensaml.xml.security.criteria.KeyAlgorithmCriteria; +import org.opensaml.xml.security.keyinfo.KeyInfoCredentialResolver; +import org.opensaml.xml.security.keyinfo.KeyInfoHelper; +import org.opensaml.xml.security.keyinfo.KeyInfoProvider; +import org.opensaml.xml.security.keyinfo.KeyInfoResolutionContext; +import org.opensaml.xml.signature.DSAKeyValue; +import org.opensaml.xml.signature.KeyValue; +import org.opensaml.xml.util.LazySet; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Implementation of {@link KeyInfoProvider} which supports {@link DSAKeyValue}. + */ +public class DSAKeyValueProvider extends AbstractKeyInfoProvider { + + /** Class logger. */ + private final Logger log = LoggerFactory.getLogger(DSAKeyValueProvider.class); + + /** {@inheritDoc} */ + public boolean handles(XMLObject keyInfoChild) { + return getDSAKeyValue(keyInfoChild) != null; + } + + /** {@inheritDoc} */ + public Collection process(KeyInfoCredentialResolver resolver, XMLObject keyInfoChild, + CriteriaSet criteriaSet, KeyInfoResolutionContext kiContext) throws SecurityException { + + DSAKeyValue keyValue = getDSAKeyValue(keyInfoChild); + if (keyValue == null) { + return null; + } + + KeyAlgorithmCriteria algorithmCriteria = criteriaSet.get(KeyAlgorithmCriteria.class); + if (algorithmCriteria != null + && algorithmCriteria.getKeyAlgorithm() != null + && ! algorithmCriteria.getKeyAlgorithm().equals("DSA")) { + log.debug("Criteria specified non-DSA key algorithm, skipping"); + return null; + } + + log.debug("Attempting to extract credential from a DSAKeyValue"); + + PublicKey pubKey = null; + try { + //TODO deal with case of incomplete DSAParams, need hook to resolve those + pubKey = KeyInfoHelper.getDSAKey(keyValue); + } catch (KeyException e) { + log.error("Error extracting DSA key value", e); + throw new SecurityException("Error extracting DSA key value", e); + } + BasicCredential cred = new BasicCredential(); + cred.setPublicKey(pubKey); + if (kiContext != null) { + cred.getKeyNames().addAll(kiContext.getKeyNames()); + } + + CredentialContext credContext = buildCredentialContext(kiContext); + if (credContext != null) { + cred.getCredentalContextSet().add(credContext); + } + + log.debug("Credential successfully extracted from DSAKeyValue"); + LazySet credentialSet = new LazySet(); + credentialSet.add(cred); + return credentialSet; + } + + /** + * Get the DSAKeyValue from the passed XML object. + * + * @param xmlObject an XML object, presumably either a {@link KeyValue} or an {@link DSAKeyValue} + * @return the DSAKeyValue which was found, or null if none + */ + protected DSAKeyValue getDSAKeyValue(XMLObject xmlObject) { + if (xmlObject == null) {return null; } + + if (xmlObject instanceof DSAKeyValue) { + return (DSAKeyValue) xmlObject; + } + + if (xmlObject instanceof KeyValue) { + return ((KeyValue) xmlObject).getDSAKeyValue(); + } + return null; + } +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/security/keyinfo/provider/InlineX509DataProvider.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/security/keyinfo/provider/InlineX509DataProvider.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/security/keyinfo/provider/InlineX509DataProvider.java 17 Aug 2012 15:17:18 -0000 1.1 @@ -0,0 +1,358 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.security.keyinfo.provider; + +import java.math.BigInteger; +import java.security.PublicKey; +import java.security.cert.CRLException; +import java.security.cert.CertificateException; +import java.security.cert.X509CRL; +import java.security.cert.X509Certificate; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; + +import javax.security.auth.x500.X500Principal; + +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.security.CriteriaSet; +import org.opensaml.xml.security.SecurityException; +import org.opensaml.xml.security.credential.Credential; +import org.opensaml.xml.security.credential.CredentialContext; +import org.opensaml.xml.security.keyinfo.KeyInfoCredentialResolver; +import org.opensaml.xml.security.keyinfo.KeyInfoHelper; +import org.opensaml.xml.security.keyinfo.KeyInfoProvider; +import org.opensaml.xml.security.keyinfo.KeyInfoResolutionContext; +import org.opensaml.xml.security.x509.BasicX509Credential; +import org.opensaml.xml.security.x509.InternalX500DNHandler; +import org.opensaml.xml.security.x509.X500DNHandler; +import org.opensaml.xml.security.x509.X509Credential; +import org.opensaml.xml.security.x509.X509Util; +import org.opensaml.xml.signature.KeyValue; +import org.opensaml.xml.signature.X509Data; +import org.opensaml.xml.signature.X509IssuerSerial; +import org.opensaml.xml.signature.X509SKI; +import org.opensaml.xml.signature.X509SubjectName; +import org.opensaml.xml.util.Base64; +import org.opensaml.xml.util.DatatypeHelper; +import org.opensaml.xml.util.LazySet; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Implementation of {@link KeyInfoProvider} which provides basic support for extracting a {@link X509Credential} + * from an {@link X509Data} child of KeyInfo. + * + * This provider supports only inline {@link X509Certificate}'s and {@link X509CRL}'s. + * If only one certificate is present, it is assumed to be the end-entity certificate containing + * the public key represented by this KeyInfo. If multiple certificates are present, and any instances + * of {@link X509SubjectName}, {@link X509IssuerSerial}, or {@link X509SKI} are also present, they + * will be used to identify the end-entity certificate, in accordance with the XML Signature specification. + * If a public key from a previously resolved {@link KeyValue} is available in the resolution context, + * it will also be used to identify the end-entity certificate. If the end-entity certificate can not + * otherwise be identified, the cert contained in the first X509Certificate element will be treated as + * the end-entity certificate. + * + */ +public class InlineX509DataProvider extends AbstractKeyInfoProvider { + + /** Class logger. */ + private final Logger log = LoggerFactory.getLogger(InlineX509DataProvider.class); + + /** Responsible for parsing and serializing X.500 names to/from {@link X500Principal} instances. */ + private X500DNHandler x500DNHandler; + + /** + * Constructor. + */ + public InlineX509DataProvider() { + x500DNHandler = new InternalX500DNHandler(); + } + + /** + * Get the handler which process X.500 distinguished names. + * + * @return returns the X500DNHandler instance + */ + public X500DNHandler getX500DNHandler() { + return x500DNHandler; + } + + /** + * Set the handler which process X.500 distinguished names. + * + * @param handler the new X500DNHandler instance + */ + public void setX500DNHandler(X500DNHandler handler) { + if (handler == null) { + throw new IllegalArgumentException("X500DNHandler may not be null"); + } + x500DNHandler = handler; + } + + /** {@inheritDoc} */ + public boolean handles(XMLObject keyInfoChild) { + return keyInfoChild instanceof X509Data; + } + + /** {@inheritDoc} */ + public Collection process(KeyInfoCredentialResolver resolver, XMLObject keyInfoChild, + CriteriaSet criteriaSet, KeyInfoResolutionContext kiContext) throws SecurityException { + + if (! handles(keyInfoChild)) { + return null; + } + + X509Data x509Data = (X509Data) keyInfoChild; + + log.debug("Attempting to extract credential from an X509Data"); + + List certs = extractCertificates(x509Data); + if (certs.isEmpty()) { + log.info("The X509Data contained no X509Certificate elements, skipping credential extraction"); + return null; + } + List crls = extractCRLs(x509Data); + + PublicKey resolvedPublicKey = null; + if (kiContext != null && kiContext.getKey() != null && kiContext.getKey() instanceof PublicKey) { + resolvedPublicKey = (PublicKey) kiContext.getKey(); + } + X509Certificate entityCert = findEntityCert(certs, x509Data, resolvedPublicKey); + if (entityCert == null) { + log.warn("The end-entity cert could not be identified, skipping credential extraction"); + return null; + } + + BasicX509Credential cred = new BasicX509Credential(); + cred.setEntityCertificate(entityCert); + cred.setCRLs(crls); + cred.setEntityCertificateChain(certs); + + if (kiContext != null) { + cred.getKeyNames().addAll(kiContext.getKeyNames()); + } + + CredentialContext credContext = buildCredentialContext(kiContext); + if (credContext != null) { + cred.getCredentalContextSet().add(credContext); + } + + LazySet credentialSet = new LazySet(); + credentialSet.add(cred); + return credentialSet; + } + + /** + * Extract CRL's from the X509Data. + * + * @param x509Data the X509Data element + * @return a list of X509CRLs + * @throws SecurityException thrown if there is an error extracting CRL's + */ + private List extractCRLs(X509Data x509Data) throws SecurityException { + List crls = null; + try { + crls = KeyInfoHelper.getCRLs(x509Data); + } catch (CRLException e) { + log.error("Error extracting CRL's from X509Data", e); + throw new SecurityException("Error extracting CRL's from X509Data", e); + } + + log.debug("Found {} X509CRLs", crls.size()); + return crls; + } + + /** + * Extract certificates from the X509Data. + * + * @param x509Data the X509Data element + * @return a list of X509Certificates + * @throws SecurityException thrown if there is an error extracting certificates + */ + private List extractCertificates(X509Data x509Data) throws SecurityException { + List certs = null; + try { + certs = KeyInfoHelper.getCertificates(x509Data); + } catch (CertificateException e) { + log.error("Error extracting certificates from X509Data", e); + throw new SecurityException("Error extracting certificates from X509Data", e); + } + log.debug("Found {} X509Certificates", certs.size()); + return certs; + } + + /** + * Find the end-entity cert in the list of certs contained in the X509Data. + * + * @param certs list of {@link java.security.cert.X509Certificate} + * @param x509Data X509Data element which might contain other info helping to finding the end-entity cert + * @param resolvedKey a key which might have previously been resolved from a KeyValue + * @return the end-entity certificate, if found + */ + protected X509Certificate findEntityCert(List certs, X509Data x509Data, PublicKey resolvedKey) { + if (certs == null || certs.isEmpty()) { + return null; + } + + // If there is only 1 certificate, treat it as the end-entity certificate + if (certs.size() == 1) { + log.debug("Single certificate was present, treating as end-entity certificate"); + return certs.get(0); + } + + X509Certificate cert = null; + + //Check against public key already resolved in resolution context + cert = findCertFromKey(certs, resolvedKey); + if (cert != null) { + log.debug("End-entity certificate resolved by matching previously resolved public key"); + return cert; + } + + //Check against any subject names + cert = findCertFromSubjectNames(certs, x509Data.getX509SubjectNames()); + if (cert != null) { + log.debug("End-entity certificate resolved by matching X509SubjectName"); + return cert; + } + + //Check against issuer serial + cert = findCertFromIssuerSerials(certs, x509Data.getX509IssuerSerials()); + if (cert != null) { + log.debug("End-entity certificate resolved by matching X509IssuerSerial"); + return cert; + } + + //Check against any subject key identifiers + cert = findCertFromSubjectKeyIdentifier(certs, x509Data.getX509SKIs()); + if (cert != null) { + log.debug("End-entity certificate resolved by matching X509SKI"); + return cert; + } + + // TODO use some heuristic algorithm to try and figure it out based on the cert list alone. + // This would be in X509Utils or somewhere else external to this class. + + // As a final fallback, treat the first cert in the X509Data element as the entity cert + log.debug("Treating the first certificate in the X509Data as the end-entity certificate"); + return certs.get(0); + } + + /** + * Find the certificate from the chain that contains the specified key. + * + * @param certs list of certificates to evaluate + * @param key key to use as search criteria + * @return the matching certificate, or null + */ + protected X509Certificate findCertFromKey(List certs, PublicKey key) { + if (key != null) { + for (X509Certificate cert : certs) { + if (cert.getPublicKey().equals(key)) { + return cert; + } + } + } + return null; + } + + /** + * Find the certificate from the chain that contains one of the specified subject names. + * + * @param certs list of certificates to evaluate + * @param names X509 subject names to use as search criteria + * @return the matching certificate, or null + */ + protected X509Certificate findCertFromSubjectNames(List certs, List names) { + for (X509SubjectName subjectName : names) { + if (! DatatypeHelper.isEmpty(subjectName.getValue())) { + X500Principal subjectX500Principal = null; + try { + subjectX500Principal = x500DNHandler.parse(subjectName.getValue()); + } catch (IllegalArgumentException e) { + log.warn("X500 subject name '{}' could not be parsed by configured X500DNHandler '{}'", + subjectName.getValue(), x500DNHandler.getClass().getName()); + return null; + } + for (X509Certificate cert : certs) { + if (cert.getSubjectX500Principal().equals(subjectX500Principal)) { + return cert; + } + } + } + } + return null; + } + + /** + * Find the certificate from the chain identified by one of the specified issuer serials. + * + * @param certs list of certificates to evaluate + * @param serials X509 issuer serials to use as search criteria + * @return the matching certificate, or null + */ + protected X509Certificate findCertFromIssuerSerials(List certs, List serials) { + for (X509IssuerSerial issuerSerial : serials) { + if (issuerSerial.getX509IssuerName() == null || issuerSerial.getX509SerialNumber() == null) { + continue; + } + String issuerNameValue = issuerSerial.getX509IssuerName().getValue(); + BigInteger serialNumber = issuerSerial.getX509SerialNumber().getValue(); + if (! DatatypeHelper.isEmpty(issuerNameValue)) { + X500Principal issuerX500Principal = null; + try { + issuerX500Principal = x500DNHandler.parse(issuerNameValue); + } catch (IllegalArgumentException e) { + log.warn("X500 issuer name '{}' could not be parsed by configured X500DNHandler '{}'", + issuerNameValue, x500DNHandler.getClass().getName()); + return null; + } + for (X509Certificate cert : certs) { + if (cert.getIssuerX500Principal().equals(issuerX500Principal) && + cert.getSerialNumber().equals(serialNumber)) { + return cert; + } + } + } + } + return null; + } + + /** + * Find the certificate from the chain that contains one of the specified subject key identifiers. + * + * @param certs list of certificates to evaluate + * @param skis X509 subject key identifiers to use as search criteria + * @return the matching certificate, or null + */ + protected X509Certificate findCertFromSubjectKeyIdentifier(List certs, List skis) { + for (X509SKI ski : skis) { + if (! DatatypeHelper.isEmpty(ski.getValue())) { + byte[] xmlValue = Base64.decode(ski.getValue()); + for (X509Certificate cert : certs) { + byte[] certValue = X509Util.getSubjectKeyIdentifier(cert); + if (certValue != null && Arrays.equals(xmlValue, certValue)) { + return cert; + } + } + } + } + return null; + } +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/security/keyinfo/provider/RSAKeyValueProvider.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/security/keyinfo/provider/RSAKeyValueProvider.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/security/keyinfo/provider/RSAKeyValueProvider.java 17 Aug 2012 15:17:18 -0000 1.1 @@ -0,0 +1,116 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.security.keyinfo.provider; + +import java.security.KeyException; +import java.security.PublicKey; +import java.util.Collection; + +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.security.CriteriaSet; +import org.opensaml.xml.security.SecurityException; +import org.opensaml.xml.security.credential.BasicCredential; +import org.opensaml.xml.security.credential.Credential; +import org.opensaml.xml.security.credential.CredentialContext; +import org.opensaml.xml.security.criteria.KeyAlgorithmCriteria; +import org.opensaml.xml.security.keyinfo.KeyInfoCredentialResolver; +import org.opensaml.xml.security.keyinfo.KeyInfoHelper; +import org.opensaml.xml.security.keyinfo.KeyInfoProvider; +import org.opensaml.xml.security.keyinfo.KeyInfoResolutionContext; +import org.opensaml.xml.signature.KeyValue; +import org.opensaml.xml.signature.RSAKeyValue; +import org.opensaml.xml.util.LazySet; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Implementation of {@link KeyInfoProvider} which supports {@link RSAKeyValue}. + */ +public class RSAKeyValueProvider extends AbstractKeyInfoProvider { + + /** Class logger. */ + private final Logger log = LoggerFactory.getLogger(RSAKeyValueProvider.class); + + /** {@inheritDoc} */ + public boolean handles(XMLObject keyInfoChild) { + return getRSAKeyValue(keyInfoChild) != null; + } + + /** {@inheritDoc} */ + public Collection process(KeyInfoCredentialResolver resolver, XMLObject keyInfoChild, + CriteriaSet criteriaSet, KeyInfoResolutionContext kiContext) throws SecurityException { + + RSAKeyValue keyValue = getRSAKeyValue(keyInfoChild); + if (keyValue == null) { + return null; + } + + KeyAlgorithmCriteria algorithmCriteria = criteriaSet.get(KeyAlgorithmCriteria.class); + if (algorithmCriteria != null && algorithmCriteria.getKeyAlgorithm() != null + && !algorithmCriteria.getKeyAlgorithm().equals("RSA")) { + log.debug("Criteria specified non-RSA key algorithm, skipping"); + return null; + } + + log.debug("Attempting to extract credential from an RSAKeyValue"); + + PublicKey pubKey = null; + try { + pubKey = KeyInfoHelper.getRSAKey(keyValue); + } catch (KeyException e) { + log.error("Error extracting RSA key value", e); + throw new SecurityException("Error extracting RSA key value", e); + } + BasicCredential cred = new BasicCredential(); + cred.setPublicKey(pubKey); + if (kiContext != null) { + cred.getKeyNames().addAll(kiContext.getKeyNames()); + } + + CredentialContext credContext = buildCredentialContext(kiContext); + if (credContext != null) { + cred.getCredentalContextSet().add(credContext); + } + + log.debug("Credential successfully extracted from RSAKeyValue"); + LazySet credentialSet = new LazySet(); + credentialSet.add(cred); + return credentialSet; + } + + /** + * Get the RSAKeyValue from the passed XML object. + * + * @param xmlObject an XML object, presumably either a {@link KeyValue} or an {@link RSAKeyValue} + * @return the RSAKeyValue which was found, or null if none + */ + protected RSAKeyValue getRSAKeyValue(XMLObject xmlObject) { + if (xmlObject == null) { + return null; + } + + if (xmlObject instanceof RSAKeyValue) { + return (RSAKeyValue) xmlObject; + } + + if (xmlObject instanceof KeyValue) { + return ((KeyValue) xmlObject).getRSAKeyValue(); + } + return null; + } +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/security/keyinfo/provider/package.html =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/security/keyinfo/provider/package.html,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/security/keyinfo/provider/package.html 17 Aug 2012 15:17:18 -0000 1.1 @@ -0,0 +1,9 @@ + + +Specific implementations of {@link org.opensaml.xml.security.keyinfo.KeyInfoProvider}. + +KeyInfo providers that, when used in conjunction with a +KeyInfoCredentialResolver, can extract typed credential information from +a KeyInfo object. + + \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/security/trust/ChainingTrustEngine.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/security/trust/ChainingTrustEngine.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/security/trust/ChainingTrustEngine.java 17 Aug 2012 15:17:21 -0000 1.1 @@ -0,0 +1,67 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.security.trust; + +import java.util.ArrayList; +import java.util.List; + +import org.opensaml.xml.security.CriteriaSet; +import org.opensaml.xml.security.SecurityException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Evaluate a token in sequence using a chain of subordinate trust engines. If the token may be established as trusted + * by any of the subordinate engines, the token is considered trusted. Otherwise it is considered untrusted. + * + * @param the token type this trust engine evaluates + */ +public class ChainingTrustEngine implements TrustEngine { + + /** Class logger. */ + private final Logger log = LoggerFactory.getLogger(ChainingTrustEngine.class); + + /** The chain of subordinate trust engines. */ + private List> engines; + + /** Constructor. */ + public ChainingTrustEngine() { + engines = new ArrayList>(); + } + + /** + * Get the list of configured trust engines which constitute the trust evaluation chain. + * + * @return the modifiable list of trust engines in the chain + */ + public List> getChain() { + return engines; + } + + /** {@inheritDoc} */ + public boolean validate(TokenType token, CriteriaSet trustBasisCriteria) throws SecurityException { + for (TrustEngine engine : engines) { + if (engine.validate(token, trustBasisCriteria)) { + log.debug("Token was trusted by chain member: {}", engine.getClass().getName()); + return true; + } + } + return false; + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/security/trust/ExplicitKeyTrustEngine.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/security/trust/ExplicitKeyTrustEngine.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/security/trust/ExplicitKeyTrustEngine.java 17 Aug 2012 15:17:21 -0000 1.1 @@ -0,0 +1,96 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.security.trust; + +import org.opensaml.xml.security.CriteriaSet; +import org.opensaml.xml.security.SecurityException; +import org.opensaml.xml.security.credential.Credential; +import org.opensaml.xml.security.credential.CredentialResolver; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Trust engine that evaluates a credential's key against key(s) expressed within a set of trusted credentials obtained + * from a trusted credential resolver. + * + * The credential being tested is valid if its public key or secret key matches the public key, or secret key + * respectively, contained within any of the trusted credentials produced by the given credential resolver. + */ +public class ExplicitKeyTrustEngine implements TrustedCredentialTrustEngine { + + /** Class logger. */ + private final Logger log = LoggerFactory.getLogger(ExplicitKeyTrustEngine.class); + + /** Resolver used for resolving trusted credentials. */ + private CredentialResolver credentialResolver; + + /** Trust evaluator. */ + private ExplicitKeyTrustEvaluator trustEvaluator; + + /** + * Constructor. + * + * @param resolver credential resolver which is used to resolve trusted credentials + */ + public ExplicitKeyTrustEngine(CredentialResolver resolver) { + if (resolver == null) { + throw new IllegalArgumentException("Credential resolver may not be null"); + } + credentialResolver = resolver; + + trustEvaluator = new ExplicitKeyTrustEvaluator(); + } + + /** {@inheritDoc} */ + public CredentialResolver getCredentialResolver() { + return credentialResolver; + } + + /** {@inheritDoc} */ + public boolean validate(Credential untrustedCredential, CriteriaSet trustBasisCriteria) throws SecurityException { + + checkParams(untrustedCredential, trustBasisCriteria); + + log.debug("Attempting to validate untrusted credential"); + Iterable trustedCredentials = getCredentialResolver().resolve(trustBasisCriteria); + + return trustEvaluator.validate(untrustedCredential, trustedCredentials); + } + + /** + * Check the parameters for required values. + * + * @param untrustedCredential the credential to be evaluated + * @param trustBasisCriteria the set of trusted credential criteria + * @throws SecurityException thrown if required values are absent or otherwise invalid + */ + protected void checkParams(Credential untrustedCredential, CriteriaSet trustBasisCriteria) + throws SecurityException { + + if (untrustedCredential == null) { + throw new SecurityException("Untrusted credential was null"); + } + if (trustBasisCriteria == null) { + throw new SecurityException("Trust basis criteria set was null"); + } + if (trustBasisCriteria.isEmpty()) { + throw new SecurityException("Trust basis criteria set was empty"); + } + } + +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/security/trust/ExplicitKeyTrustEvaluator.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/security/trust/ExplicitKeyTrustEvaluator.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/security/trust/ExplicitKeyTrustEvaluator.java 17 Aug 2012 15:17:21 -0000 1.1 @@ -0,0 +1,116 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.security.trust; + +import java.security.Key; + +import org.opensaml.xml.security.credential.Credential; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Auxillary trust evaluator for evaluating an untrusted key or credential against a trusted key or credential. Trust is + * established if the untrusted key (or public key or symmetric key from the untrusted credential) is matches one of the + * trusted keys supplied. + * + */ +public class ExplicitKeyTrustEvaluator { + + /** Class logger. */ + private final Logger log = LoggerFactory.getLogger(ExplicitKeyTrustEvaluator.class); + + /** + * Evaluate trust. + * + * @param untrustedKey the untrusted key to evaluate + * @param trustedKey basis for trust + * @return true if trust can be established, false otherwise + */ + public boolean validate(Key untrustedKey, Key trustedKey) { + return untrustedKey.equals(trustedKey); + } + + /** + * Evaluate trust. + * + * @param untrustedKey the untrusted key to evaluate + * @param trustedKeys basis for trust + * @return true if trust can be established, false otherwise + */ + public boolean validate(Key untrustedKey, Iterable trustedKeys) { + for (Key trustedKey : trustedKeys) { + if (untrustedKey.equals(trustedKey)) { + return true; + } + } + return false; + } + + /** + * Evaluate trust. + * + * @param untrustedCredential the untrusted credential to evaluate + * @param trustedCredential basis for trust + * @return true if trust can be established, false otherwise + */ + public boolean validate(Credential untrustedCredential, Credential trustedCredential) { + + Key untrustedKey = null; + Key trustedKey = null; + if (untrustedCredential.getPublicKey() != null) { + untrustedKey = untrustedCredential.getPublicKey(); + trustedKey = trustedCredential.getPublicKey(); + } else { + untrustedKey = untrustedCredential.getSecretKey(); + trustedKey = trustedCredential.getSecretKey(); + } + if (untrustedKey == null) { + log.debug("Untrusted credential contained no key, unable to evaluate"); + return false; + } else if (trustedKey == null) { + log.debug("Trusted credential contained no key of the appropriate type, unable to evaluate"); + return false; + } + + if (validate(untrustedKey, trustedKey)) { + log.debug("Successfully validated untrusted credential against trusted key"); + return true; + } + + log.debug("Failed to validate untrusted credential against trusted key"); + return false; + } + + /** + * Evaluate trust. + * + * @param untrustedCredential the untrusted credential to evaluate + * @param trustedCredentials basis for trust + * @return true if trust can be established, false otherwise + */ + public boolean validate(Credential untrustedCredential, Iterable trustedCredentials) { + + for (Credential trustedCredential : trustedCredentials) { + if (validate(untrustedCredential, trustedCredential)) { + return true; + } + } + return false; + } + +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/security/trust/ExplicitX509CertificateTrustEngine.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/security/trust/ExplicitX509CertificateTrustEngine.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/security/trust/ExplicitX509CertificateTrustEngine.java 17 Aug 2012 15:17:21 -0000 1.1 @@ -0,0 +1,98 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.security.trust; + +import org.opensaml.xml.security.CriteriaSet; +import org.opensaml.xml.security.SecurityException; +import org.opensaml.xml.security.credential.Credential; +import org.opensaml.xml.security.credential.CredentialResolver; +import org.opensaml.xml.security.x509.X509Credential; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Trust engine that evaluates a credential's X.509 certificate against certificates expressed within a set of trusted + * credentials obtained from a credential resolver. + * + * The credential being tested is valid if its entity certificate matches the entity certificate contained within any of + * the trusted credentials produced by the given credential resolver. + */ +public class ExplicitX509CertificateTrustEngine implements TrustedCredentialTrustEngine { + + /** Class logger. */ + private final Logger log = LoggerFactory.getLogger(ExplicitX509CertificateTrustEngine.class); + + /** Resolver used for resolving trusted credentials. */ + private CredentialResolver credentialResolver; + + /** Trust evaluator. */ + private ExplicitX509CertificateTrustEvaluator trustEvaluator; + + /** + * Constructor. + * + * @param resolver credential resolver which is used to resolve trusted credentials + */ + public ExplicitX509CertificateTrustEngine(CredentialResolver resolver) { + if (resolver == null) { + throw new IllegalArgumentException("Credential resolver may not be null"); + } + credentialResolver = resolver; + + trustEvaluator = new ExplicitX509CertificateTrustEvaluator(); + } + + /** {@inheritDoc} */ + public CredentialResolver getCredentialResolver() { + return credentialResolver; + } + + /** {@inheritDoc} */ + public boolean validate(X509Credential untrustedCredential, CriteriaSet trustBasisCriteria) + throws SecurityException { + + checkParams(untrustedCredential, trustBasisCriteria); + + log.debug("Attempting to validate untrusted credential"); + Iterable trustedCredentials = getCredentialResolver().resolve(trustBasisCriteria); + + return trustEvaluator.validate(untrustedCredential, trustedCredentials); + } + + /** + * Check the parameters for required values. + * + * @param untrustedCredential the signature to be evaluated + * @param trustBasisCriteria the set of trusted credential criteria + * @throws SecurityException thrown if required values are absent or otherwise invalid + */ + protected void checkParams(X509Credential untrustedCredential, CriteriaSet trustBasisCriteria) + throws SecurityException { + + if (untrustedCredential == null) { + throw new SecurityException("Untrusted credential was null"); + } + if (trustBasisCriteria == null) { + throw new SecurityException("Trust basis criteria set was null"); + } + if (trustBasisCriteria.isEmpty()) { + throw new SecurityException("Trust basis criteria set was empty"); + } + } + +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/security/trust/ExplicitX509CertificateTrustEvaluator.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/security/trust/ExplicitX509CertificateTrustEvaluator.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/security/trust/ExplicitX509CertificateTrustEvaluator.java 17 Aug 2012 15:17:21 -0000 1.1 @@ -0,0 +1,116 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.security.trust; + +import java.security.cert.X509Certificate; + +import org.opensaml.xml.security.credential.Credential; +import org.opensaml.xml.security.x509.X509Credential; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Auxillary trust evaluator for evaluating an untrusted X509 certificate or credential against a trusted certificate or + * credential. Trust is established if the untrusted certificate supplied (or the certificate obtained from the + * untrusted credential's {@link X509Credential#getEntityCertificate()}) matches one of the trusted certificates + * supplied. + */ +public class ExplicitX509CertificateTrustEvaluator { + + /** Class logger. */ + private final Logger log = LoggerFactory.getLogger(ExplicitX509CertificateTrustEvaluator.class); + + /** + * Evaluate trust. + * + * @param untrustedCertificate the untrusted certificate to evaluate + * @param trustedCertificate basis for trust + * @return true if trust can be established, false otherwise + */ + public boolean validate(X509Certificate untrustedCertificate, X509Certificate trustedCertificate) { + return untrustedCertificate.equals(trustedCertificate); + } + + /** + * Evaluate trust. + * + * @param untrustedCertificate the untrusted certificate to evaluate + * @param trustedCertificates basis for trust + * @return true if trust can be established, false otherwise + */ + public boolean validate(X509Certificate untrustedCertificate, Iterable trustedCertificates) { + for (X509Certificate trustedCertificate : trustedCertificates) { + if (untrustedCertificate.equals(trustedCertificate)) { + return true; + } + } + return false; + } + + /** + * Evaluate trust. + * + * @param untrustedCredential the untrusted X509Credential to evaluate + * @param trustedCredential basis for trust + * @return true if trust can be established, false otherwise + */ + public boolean validate(X509Credential untrustedCredential, X509Credential trustedCredential) { + + X509Certificate untrustedCertificate = untrustedCredential.getEntityCertificate(); + X509Certificate trustedCertificate = trustedCredential.getEntityCertificate(); + if (untrustedCertificate == null) { + log.debug("Untrusted credential contained no entity certificate, unable to evaluate"); + return false; + } else if (trustedCertificate == null) { + log.debug("Trusted credential contained no entity certificate, unable to evaluate"); + return false; + } + + if (validate(untrustedCertificate, trustedCertificate)) { + log.debug("Successfully validated untrusted credential against trusted certificate"); + return true; + } + + log.debug("Failed to validate untrusted credential against trusted certificate"); + return false; + } + + /** + * Evaluate trust. + * + * @param untrustedCredential the untrusted X509Credential to evaluate + * @param trustedCredentials basis for trust + * @return true if trust can be established, false otherwise + */ + public boolean validate(X509Credential untrustedCredential, Iterable trustedCredentials) { + + for (Credential trustedCredential : trustedCredentials) { + if (!(trustedCredential instanceof X509Credential)) { + log.debug("Skipping evaluation against trusted, non-X509Credential"); + continue; + } + X509Credential trustedX509Credential = (X509Credential) trustedCredential; + if (validate(untrustedCredential, trustedX509Credential)) { + return true; + } + } + + return false; + } + +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/security/trust/TrustEngine.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/security/trust/TrustEngine.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/security/trust/TrustEngine.java 17 Aug 2012 15:17:21 -0000 1.1 @@ -0,0 +1,44 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.security.trust; + +import org.opensaml.xml.security.CriteriaSet; +import org.opensaml.xml.security.SecurityException; + +/** + * Evaluates the trustworthiness and validity of a token against + * implementation-specific requirements. + * + * @param the token type this trust engine evaluates + */ +public interface TrustEngine { + + /** + * Validates the token against trusted information obtained in an + * implementation-specific manner. + * + * @param token security token to validate + * @param trustBasisCriteria criteria used to describe and/or resolve the information + * which serves as the basis for trust evaluation + * + * @return true if the token is trusted and valid, false if not + * + * @throws SecurityException thrown if there is a problem validating the security token + */ + public boolean validate(TokenType token, CriteriaSet trustBasisCriteria) throws SecurityException; +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/security/trust/TrustedCredentialTrustEngine.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/security/trust/TrustedCredentialTrustEngine.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/security/trust/TrustedCredentialTrustEngine.java 17 Aug 2012 15:17:21 -0000 1.1 @@ -0,0 +1,39 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.security.trust; + +import org.opensaml.xml.security.credential.CredentialResolver; + +/** + * Evaluates the trustworthiness and validity of a token against + * implementation-specific requirements based on trusted credentials + * obtained via a credential resolver. + * + * @param the token type this trust engine evaluates + */ +public interface TrustedCredentialTrustEngine extends TrustEngine { + + /** + * Gets the credential resolver used to recover trusted credentials that + * may be used to validate tokens. + * + * @return credential resolver used to recover trusted credentials + * that may be used to validate tokens + */ + public CredentialResolver getCredentialResolver(); +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/security/trust/package.html =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/security/trust/package.html,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/security/trust/package.html 17 Aug 2012 15:17:21 -0000 1.1 @@ -0,0 +1,6 @@ + + +Interfaces and classes used to evaluate the trustworthiness +and validity of {@link org.opensaml.xml.security.credential.Credential}s + + Index: 3rdParty_sources/xmltooling/org/opensaml/xml/security/x509/BasicPKIXValidationInformation.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/security/x509/BasicPKIXValidationInformation.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/security/x509/BasicPKIXValidationInformation.java 17 Aug 2012 15:16:59 -0000 1.1 @@ -0,0 +1,67 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.security.x509; + +import java.security.cert.X509CRL; +import java.security.cert.X509Certificate; +import java.util.Collection; + +/** + * Basic implementation of {@link PKIXValidationInformation}. + */ +public class BasicPKIXValidationInformation implements PKIXValidationInformation { + + /** Certs used as the trust anchors. */ + private Collection trustAnchors; + + /** CRLs used during validation. */ + private Collection trustedCRLs; + + /** Max verification depth during PKIX validation. */ + private Integer verificationDepth; + + /** + * Constructor. + * + * @param anchors certs used as trust anchors during validation + * @param crls CRLs used during validation + * @param depth max verification path depth + */ + public BasicPKIXValidationInformation(Collection anchors, Collection crls, + Integer depth) { + + trustAnchors = anchors; + trustedCRLs = crls; + verificationDepth = depth; + } + + /** {@inheritDoc} */ + public Collection getCRLs() { + return trustedCRLs; + } + + /** {@inheritDoc} */ + public Collection getCertificates() { + return trustAnchors; + } + + /** {@inheritDoc} */ + public Integer getVerificationDepth() { + return verificationDepth; + } +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/security/x509/BasicX509Credential.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/security/x509/BasicX509Credential.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/security/x509/BasicX509Credential.java 17 Aug 2012 15:16:59 -0000 1.1 @@ -0,0 +1,129 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.security.x509; + +import java.security.PublicKey; +import java.security.cert.X509CRL; +import java.security.cert.X509Certificate; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; + +import javax.crypto.SecretKey; + +import org.opensaml.xml.security.credential.BasicCredential; +import org.opensaml.xml.security.credential.Credential; + +/** + * A basic implementation of {@link X509Credential}. + */ +public class BasicX509Credential extends BasicCredential implements X509Credential { + + /** Entity certificate. */ + private X509Certificate entityCert; + + /** Entity certificate chain, must include entity certificate. */ + private Collection entityCertChain; + + /** CRLs for this credential. */ + private Collection crls; + + /** {@inheritDoc} */ + public Class getCredentialType() { + return X509Credential.class; + } + + /** {@inheritDoc} */ + public Collection getCRLs() { + return crls; + } + + /** + * Sets the CRLs for this credential. + * + * @param newCRLs CRLs for this credential + */ + public void setCRLs(Collection newCRLs) { + crls = newCRLs; + } + + /** {@inheritDoc} */ + public X509Certificate getEntityCertificate() { + return entityCert; + } + + /** + * Sets the entity certificate for this credential. + * + * @param cert entity certificate for this credential + */ + public void setEntityCertificate(X509Certificate cert) { + entityCert = cert; + if (cert != null) { + setPublicKey(cert.getPublicKey()); + } else { + setPublicKey(null); + } + } + + /** {@inheritDoc} */ + public Collection getEntityCertificateChain() { + if (entityCertChain == null && entityCert != null) { + HashSet constructedChain = new HashSet(5); + constructedChain.add(entityCert); + return constructedChain; + } + + return entityCertChain; + } + + /** + * Sets the entity certificate chain for this credential. This MUST include the entity + * certificate. + * + * @param certs ntity certificate chain for this credential + */ + public void setEntityCertificateChain(Collection certs) { + entityCertChain = new ArrayList(certs); + } + + /** {@inheritDoc} */ + public void setPublicKey(PublicKey key) { + if (entityCert != null) { + if (! entityCert.getPublicKey().equals(key)) { + throw new IllegalArgumentException("X509Credential already contains a certificate " + + "with a different public key"); + } + } + super.setPublicKey(key); + } + + /** {@inheritDoc} */ + public void setSecretKey(SecretKey key) { + if (key != null) { + throw new UnsupportedOperationException("Secret (symmetric) key may not be set " + + "on an X509Credential instance"); + } + } + + /** {@inheritDoc} */ + public SecretKey getSecretKey() { + return null; + } + +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/security/x509/BasicX509CredentialNameEvaluator.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/security/x509/BasicX509CredentialNameEvaluator.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/security/x509/BasicX509CredentialNameEvaluator.java 17 Aug 2012 15:16:59 -0000 1.1 @@ -0,0 +1,372 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.security.x509; + +import java.security.cert.X509Certificate; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import javax.security.auth.x500.X500Principal; + +import org.opensaml.xml.security.SecurityException; +import org.opensaml.xml.util.DatatypeHelper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * A basic implementaion of {@link X509CredentialNameEvaluator} which evaluates various identifiers + * extracted from an {@link X509Credential}'s entity certificate against a set of trusted names. + * + *

+ * Supported types of entity certificate-derived names for name checking purposes are: + *

    + *
  1. Subject alternative names.
  2. + *
  3. The first (i.e. most specific) common name (CN) from the subject distinguished name.
  4. + *
  5. The complete subject distinguished name.
  6. + *
+ *

+ * + *

+ * Name checking is enabled by default for all of the supported name types. The types of subject alternative names to + * process are specified by using the appropriate constant values defined in {@link X509Util}. By default the following + * types of subject alternative names are checked: DNS ({@link X509Util#DNS_ALT_NAME}) + * and URI ({@link X509Util#URI_ALT_NAME}). + *

+ * + *

+ * The subject distinguished name from the entity certificate is compared to the trusted key names for complete DN + * matching purposes by parsing each trusted key name into an {@link X500Principal} as returned by the configured + * instance of {@link X500DNHandler}. The resulting distinguished name is then compared with the certificate subject + * using {@link X500Principal#equals(Object)}. The default X500DNHandler used is {@link InternalX500DNHandler}. + *

+ * + */ +public class BasicX509CredentialNameEvaluator implements X509CredentialNameEvaluator { + + /** Class logger. */ + private final Logger log = LoggerFactory.getLogger(BasicX509CredentialNameEvaluator.class); + + /** Flag as to whether to perform name checking using credential's subject alt names. */ + private boolean checkSubjectAltNames; + + /** Flag as to whether to perform name checking using credential's subject DN's common name (CN). */ + private boolean checkSubjectDNCommonName; + + /** Flag as to whether to perform name checking using credential's subject DN. */ + private boolean checkSubjectDN; + + /** The set of types of subject alternative names to process. */ + private Set subjectAltNameTypes; + + /** Responsible for parsing and serializing X.500 names to/from {@link X500Principal} instances. */ + private X500DNHandler x500DNHandler; + + /** Constructor. */ + public BasicX509CredentialNameEvaluator() { + + x500DNHandler = new InternalX500DNHandler(); + subjectAltNameTypes = new HashSet(5); + + // Add some defaults + setCheckSubjectAltNames(true); + setCheckSubjectDNCommonName(true); + setCheckSubjectDN(true); + subjectAltNameTypes.add(X509Util.DNS_ALT_NAME); + subjectAltNameTypes.add(X509Util.URI_ALT_NAME); + } + + /** + * Gets whether any of the supported name type checking is currently enabled. + * + * @return true if any of the supported name type checking categories is currently enabled, false otherwise + */ + public boolean isNameCheckingActive() { + return checkSubjectAltNames() || checkSubjectDNCommonName() || checkSubjectDN(); + } + + /** + * The set of types of subject alternative names to process. + * + * Name types are represented using the constant OID tag name values defined in {@link X509Util}. + * + * + * @return the modifiable set of alt name identifiers + */ + public Set getSubjectAltNameTypes() { + return subjectAltNameTypes; + } + + /** + * Gets whether to check the credential's entity certificate subject alt names against the trusted key + * name values. + * + * @return whether to check the credential's entity certificate subject alt names against the trusted key + * names + */ + public boolean checkSubjectAltNames() { + return checkSubjectAltNames; + } + + /** + * Sets whether to check the credential's entity certificate subject alt names against the trusted key + * name values. + * + * @param check whether to check the credential's entity certificate subject alt names against the trusted + * key names + */ + public void setCheckSubjectAltNames(boolean check) { + checkSubjectAltNames = check; + } + + /** + * Gets whether to check the credential's entity certificate subject DN's common name (CN) against the + * trusted key name values. + * + * @return whether to check the credential's entity certificate subject DN's CN against the trusted key + * names + */ + public boolean checkSubjectDNCommonName() { + return checkSubjectDNCommonName; + } + + /** + * Sets whether to check the credential's entity certificate subject DN's common name (CN) against the + * trusted key name values. + * + * @param check whether to check the credential's entity certificate subject DN's CN against the trusted + * key names + */ + public void setCheckSubjectDNCommonName(boolean check) { + checkSubjectDNCommonName = check; + } + + /** + * Gets whether to check the credential's entity certificate subject DN against the trusted key name + * values. + * + * @return whether to check the credential's entity certificate subject DN against the trusted key names + */ + public boolean checkSubjectDN() { + return checkSubjectDN; + } + + /** + * Sets whether to check the credential's entity certificate subject DN against the trusted key name + * values. + * + * @param check whether to check the credential's entity certificate subject DN against the trusted key + * names + */ + public void setCheckSubjectDN(boolean check) { + checkSubjectDN = check; + } + + /** + * Get the handler which process X.500 distinguished names. + * + * Defaults to {@link InternalX500DNHandler}. + * + * @return returns the X500DNHandler instance + */ + public X500DNHandler getX500DNHandler() { + return x500DNHandler; + } + + /** + * Set the handler which process X.500 distinguished names. + * + * Defaults to {@link InternalX500DNHandler}. + * + * @param handler the new X500DNHandler instance + */ + public void setX500DNHandler(X500DNHandler handler) { + if (handler == null) { + throw new IllegalArgumentException("X500DNHandler may not be null"); + } + x500DNHandler = handler; + } + + /** + * {@inheritDoc} + * + *

+ * If the set of trusted names is null or empty, or if no supported name types are configured to be + * checked, then the evaluation is considered successful. + *

+ * + */ + @SuppressWarnings("unchecked") + public boolean evaluate(X509Credential credential, Set trustedNames) throws SecurityException { + if (!isNameCheckingActive()) { + log.debug("No trusted name options are active, skipping name evaluation"); + return true; + } else if (trustedNames == null || trustedNames.isEmpty()) { + log.debug("Supplied trusted names are null or empty, skipping name evaluation"); + return true; + } + + if (log.isDebugEnabled()) { + log.debug("Checking trusted names against credential: {}", + X509Util.getIdentifiersToken(credential, x500DNHandler)); + log.debug("Trusted names being evaluated are: {}", + trustedNames.toString()); + } + return processNameChecks(credential, trustedNames); + } + + /** + * Process any name checks that are enabled. + * + * @param credential the credential for the entity to validate + * @param trustedNames trusted names against which the credential will be evaluated + * @return if true the name check succeeds, false if not + */ + protected boolean processNameChecks(X509Credential credential, Set trustedNames) { + X509Certificate entityCertificate = credential.getEntityCertificate(); + + if (checkSubjectAltNames()) { + if (processSubjectAltNames(entityCertificate, trustedNames)) { + if (log.isDebugEnabled()) { + log.debug("Credential {} passed name check based on subject alt names.", + X509Util.getIdentifiersToken(credential, x500DNHandler)); + } + return true; + } + } + + if (checkSubjectDNCommonName()) { + if (processSubjectDNCommonName(entityCertificate, trustedNames)) { + if (log.isDebugEnabled()) { + log.debug("Credential {} passed name check based on subject common name.", + X509Util.getIdentifiersToken(credential, x500DNHandler)); + } + return true; + } + } + + if (checkSubjectDN()) { + if (processSubjectDN(entityCertificate, trustedNames)) { + if (log.isDebugEnabled()) { + log.debug("Credential {} passed name check based on subject DN.", + X509Util.getIdentifiersToken(credential, x500DNHandler)); + } + return true; + } + } + + log.error("Credential failed name check: " + + X509Util.getIdentifiersToken(credential, x500DNHandler)); + return false; + } + + /** + * Process name checking for a certificate subject DN's common name. + * + * @param certificate the certificate to process + * @param trustedNames the set of trusted names + * + * @return true if the subject DN common name matches the set of trusted names, false otherwise + * + */ + protected boolean processSubjectDNCommonName(X509Certificate certificate, Set trustedNames) { + log.debug("Processing subject DN common name"); + X500Principal subjectPrincipal = certificate.getSubjectX500Principal(); + List commonNames = X509Util.getCommonNames(subjectPrincipal); + if (commonNames == null || commonNames.isEmpty()) { + return false; + } + // TODO We only check the first one returned by X509Util. Maybe we should check all, + // if there are multiple CN AVA's from the same (first) RDN. + String commonName = commonNames.get(0); + log.debug("Extracted common name from certificate: {}", commonName); + + if (DatatypeHelper.isEmpty(commonName)) { + return false; + } + if (trustedNames.contains(commonName)) { + log.debug("Matched subject DN common name to trusted names: {}", commonName); + return true; + } else { + return false; + } + } + + /** + * Process name checking for the certificate subject DN. + * + * @param certificate the certificate to process + * @param trustedNames the set of trusted names + * + * @return true if the subject DN matches the set of trusted names, false otherwise + */ + protected boolean processSubjectDN(X509Certificate certificate, Set trustedNames) { + log.debug("Processing subject DN"); + X500Principal subjectPrincipal = certificate.getSubjectX500Principal(); + + if (log.isDebugEnabled()) { + log.debug("Extracted X500Principal from certificate: {}", x500DNHandler.getName(subjectPrincipal)); + } + for (String trustedName : trustedNames) { + X500Principal trustedNamePrincipal = null; + try { + trustedNamePrincipal = x500DNHandler.parse(trustedName); + log.debug("Evaluating principal successfully parsed from trusted name: {}", trustedName); + if (subjectPrincipal.equals(trustedNamePrincipal)) { + if (log.isDebugEnabled()) { + log.debug("Matched subject DN to trusted names: {}", x500DNHandler.getName(subjectPrincipal)); + } + return true; + } + } catch (IllegalArgumentException e) { + // Do nothing, probably wasn't a distinguished name. + // TODO maybe try and match only the "suspected" DN values above + // - maybe match with regex for '='or something + log.debug("Trusted name was not a DN or could not be parsed: {}", trustedName); + continue; + } + } + return false; + } + + /** + * Process name checking for the subject alt names within the certificate. + * + * @param certificate the certificate to process + * @param trustedNames the set of trusted names + * + * @return true if one of the subject alt names matches the set of trusted names, false otherwise + */ + protected boolean processSubjectAltNames(X509Certificate certificate, Set trustedNames) { + log.debug("Processing subject alt names"); + Integer[] nameTypes = new Integer[subjectAltNameTypes.size()]; + subjectAltNameTypes.toArray(nameTypes); + List altNames = X509Util.getAltNames(certificate, nameTypes); + + log.debug("Extracted subject alt names from certificate: {}", altNames); + + for (Object altName : altNames) { + if (trustedNames.contains(altName)) { + log.debug("Matched subject alt name to trusted names: {}", altName.toString()); + return true; + } + } + return false; + } + +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/security/x509/CertPathPKIXTrustEvaluator.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/security/x509/CertPathPKIXTrustEvaluator.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/security/x509/CertPathPKIXTrustEvaluator.java 17 Aug 2012 15:16:59 -0000 1.1 @@ -0,0 +1,395 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.security.x509; + +import java.security.GeneralSecurityException; +import java.security.cert.CRL; +import java.security.cert.CertPathBuilder; +import java.security.cert.CertPathBuilderException; +import java.security.cert.CertStore; +import java.security.cert.CertStoreException; +import java.security.cert.Certificate; +import java.security.cert.CollectionCertStoreParameters; +import java.security.cert.PKIXBuilderParameters; +import java.security.cert.PKIXCertPathBuilderResult; +import java.security.cert.TrustAnchor; +import java.security.cert.X509CRL; +import java.security.cert.X509CertSelector; +import java.security.cert.X509Certificate; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Date; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.opensaml.xml.security.SecurityException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * An implementation of {@link PKIXTrustEvaluator} that is based on the Java CertPath API. + */ +public class CertPathPKIXTrustEvaluator implements PKIXTrustEvaluator { + + /** Class logger. */ + private final Logger log = LoggerFactory.getLogger(CertPathPKIXTrustEvaluator.class); + + /** Responsible for parsing and serializing X.500 names to/from {@link X500Principal} instances. */ + private X500DNHandler x500DNHandler; + + /** Options influencing processing behavior. */ + private PKIXValidationOptions options; + + /** Constructor. */ + public CertPathPKIXTrustEvaluator() { + options = new PKIXValidationOptions(); + x500DNHandler = new InternalX500DNHandler(); + } + + /** + * Constructor. + * + * @param newOptions PKIX validation options + */ + public CertPathPKIXTrustEvaluator(PKIXValidationOptions newOptions) { + if (newOptions == null) { + throw new IllegalArgumentException("PKIXValidationOptions may not be null"); + } + options = newOptions; + x500DNHandler = new InternalX500DNHandler(); + } + + /** {@inheritDoc} */ + public PKIXValidationOptions getPKIXValidationOptions() { + return options; + } + + /** + * Set the desired PKIX validation options set. + * + * @param newOptions the new set of options + */ + public void setPKIXValidationOptions(PKIXValidationOptions newOptions) { + if (newOptions == null) { + throw new IllegalArgumentException("PKIXValidationOptions may not be null"); + } + options = newOptions; + } + + /** + * Get the handler which process X.500 distinguished names. + * + * Defaults to {@link InternalX500DNHandler}. + * + * @return returns the X500DNHandler instance + */ + public X500DNHandler getX500DNHandler() { + return x500DNHandler; + } + + /** + * Set the handler which process X.500 distinguished names. + * + * Defaults to {@link InternalX500DNHandler}. + * + * @param handler the new X500DNHandler instance + */ + public void setX500DNHandler(X500DNHandler handler) { + if (handler == null) { + throw new IllegalArgumentException("X500DNHandler may not be null"); + } + x500DNHandler = handler; + } + + /** {@inheritDoc} */ + public boolean validate(PKIXValidationInformation validationInfo, X509Credential untrustedCredential) + throws SecurityException { + + if (log.isDebugEnabled()) { + log.debug("Attempting PKIX path validation on untrusted credential: {}", + X509Util.getIdentifiersToken(untrustedCredential, x500DNHandler)); + } + + try { + PKIXBuilderParameters params = getPKIXBuilderParameters(validationInfo, untrustedCredential); + + log.trace("Building certificate validation path"); + + CertPathBuilder builder = CertPathBuilder.getInstance("PKIX"); + PKIXCertPathBuilderResult buildResult = (PKIXCertPathBuilderResult) builder.build(params); + if (log.isDebugEnabled()) { + logCertPathDebug(buildResult, untrustedCredential.getEntityCertificate()); + log.debug("PKIX validation succeeded for untrusted credential: {}", + X509Util.getIdentifiersToken(untrustedCredential, x500DNHandler)); + } + return true; + + } catch (CertPathBuilderException e) { + if (log.isTraceEnabled()) { + log.trace("PKIX path construction failed for untrusted credential: " + + X509Util.getIdentifiersToken(untrustedCredential, x500DNHandler), e); + } else { + log.error("PKIX path construction failed for untrusted credential: " + + X509Util.getIdentifiersToken(untrustedCredential, x500DNHandler) + ": " + e.getMessage()); + } + return false; + } catch (GeneralSecurityException e) { + log.error("PKIX validation failure", e); + throw new SecurityException("PKIX validation failure", e); + } + } + + /** + * Creates the set of PKIX builder parameters to use when building the cert path builder. + * + * @param validationInfo PKIX validation information + * @param untrustedCredential credential to be validated + * + * @return PKIX builder params + * + * @throws GeneralSecurityException thrown if the parameters can not be created + */ + protected PKIXBuilderParameters getPKIXBuilderParameters(PKIXValidationInformation validationInfo, + X509Credential untrustedCredential) throws GeneralSecurityException { + Set trustAnchors = getTrustAnchors(validationInfo); + if (trustAnchors == null || trustAnchors.isEmpty()) { + throw new GeneralSecurityException( + "Unable to validate X509 certificate, no trust anchors found in the PKIX validation information"); + } + + X509CertSelector selector = new X509CertSelector(); + selector.setCertificate(untrustedCredential.getEntityCertificate()); + + log.trace("Adding trust anchors to PKIX validator parameters"); + PKIXBuilderParameters params = new PKIXBuilderParameters(trustAnchors, selector); + + Integer effectiveVerifyDepth = getEffectiveVerificationDepth(validationInfo); + log.trace("Setting max verification depth to: {} ", effectiveVerifyDepth); + params.setMaxPathLength(effectiveVerifyDepth); + + CertStore certStore = buildCertStore(validationInfo, untrustedCredential); + params.addCertStore(certStore); + + boolean isForceRevocationEnabled = false; + boolean forcedRevocation = false; + if (options instanceof CertPathPKIXValidationOptions) { + CertPathPKIXValidationOptions certpathOptions = (CertPathPKIXValidationOptions) options; + isForceRevocationEnabled = certpathOptions.isForceRevocationEnabled(); + forcedRevocation = certpathOptions.isRevocationEnabled(); + } + + if (isForceRevocationEnabled) { + log.trace("PKIXBuilderParameters#setRevocationEnabled is being forced to: {}", forcedRevocation); + params.setRevocationEnabled(forcedRevocation); + } else { + if (storeContainsCRLs(certStore)) { + log.trace("At least one CRL was present in cert store, enabling revocation checking"); + params.setRevocationEnabled(true); + } else { + log.trace("No CRLs present in cert store, disabling revocation checking"); + params.setRevocationEnabled(false); + } + } + + return params; + } + + /** + * Determine whether there are any CRL's in the {@link CertStore} that is to be used. + * + * @param certStore the cert store that will be used for validation + * @return true if the store contains at least 1 CRL instance, false otherwise + */ + protected boolean storeContainsCRLs(CertStore certStore) { + Collection crls = null; + try { + //Save some cycles and memory: Collection cert store allows null as specifier to return all. + //crls = certStore.getCRLs( new X509CRLSelector() ); + crls = certStore.getCRLs(null); + } catch (CertStoreException e) { + log.error("Error examining cert store for CRL's, treating as if no CRL's present", e); + return false; + } + if (crls != null && !crls.isEmpty()) { + return true; + } + return false; + } + + /** + * Get the effective maximum path depth to use when constructing PKIX cert path builder parameters. + * + * @param validationInfo PKIX validation information + * @return the effective max verification depth to use + */ + protected Integer getEffectiveVerificationDepth(PKIXValidationInformation validationInfo) { + Integer effectiveVerifyDepth = validationInfo.getVerificationDepth(); + if (effectiveVerifyDepth == null) { + effectiveVerifyDepth = options.getDefaultVerificationDepth(); + } + return effectiveVerifyDepth; + } + + /** + * Creates the collection of trust anchors to use during validation. + * + * @param validationInfo PKIX validation information + * + * @return trust anchors to use during validation + */ + protected Set getTrustAnchors(PKIXValidationInformation validationInfo) { + Collection validationCertificates = validationInfo.getCertificates(); + + log.trace("Constructing trust anchors for PKIX validation"); + Set trustAnchors = new HashSet(); + for (X509Certificate cert : validationCertificates) { + trustAnchors.add(buildTrustAnchor(cert)); + } + + if (log.isTraceEnabled()) { + for (TrustAnchor anchor : trustAnchors) { + log.trace("TrustAnchor: {}", anchor.toString()); + } + } + + return trustAnchors; + } + + /** + * Build a trust anchor from the given X509 certificate. + * + * This could for example be extended by subclasses to add custom name constraints, if desired. + * + * @param cert the certificate which serves as the trust anchor + * @return the newly constructed TrustAnchor + */ + protected TrustAnchor buildTrustAnchor(X509Certificate cert) { + return new TrustAnchor(cert, null); + } + + /** + * Creates the certificate store that will be used during validation. + * + * @param validationInfo PKIX validation information + * @param untrustedCredential credential to be validated + * + * @return certificate store used during validation + * + * @throws GeneralSecurityException thrown if the certificate store can not be created from the cert and CRL + * material + */ + protected CertStore buildCertStore(PKIXValidationInformation validationInfo, X509Credential untrustedCredential) + throws GeneralSecurityException { + + log.trace("Creating cert store to use during path validation"); + + log.trace("Adding entity certificate chain to cert store"); + List storeMaterial = new ArrayList(untrustedCredential.getEntityCertificateChain()); + if (log.isTraceEnabled()) { + for (X509Certificate cert : untrustedCredential.getEntityCertificateChain()) { + log.trace(String.format("Added X509Certificate from entity cert chain to cert store " + + "with subject name '%s' issued by '%s' with serial number '%s'", + x500DNHandler.getName(cert.getSubjectX500Principal()), + x500DNHandler.getName(cert.getIssuerX500Principal()), + cert.getSerialNumber().toString())); + } + } + + Date now = new Date(); + + if (validationInfo.getCRLs() != null && !validationInfo.getCRLs().isEmpty()) { + log.trace("Processing CRL's from PKIX info set"); + addCRLsToStoreMaterial(storeMaterial, validationInfo.getCRLs(), now); + } + + if (untrustedCredential.getCRLs() != null && !untrustedCredential.getCRLs().isEmpty() + && options.isProcessCredentialCRLs()) { + log.trace("Processing CRL's from untrusted credential"); + addCRLsToStoreMaterial(storeMaterial, untrustedCredential.getCRLs(), now); + } + + return CertStore.getInstance("Collection", new CollectionCertStoreParameters(storeMaterial)); + } + + /** + * Add CRL's from the specified collection to the list of certs and CRL's being collected + * for the CertStore. + * + * @param storeMaterial list of certs and CRL's to be updated. + * @param crls collection of CRL's to be processed + * @param now current date/time + */ + protected void addCRLsToStoreMaterial(List storeMaterial, Collection crls, Date now) { + for (X509CRL crl : crls) { + boolean isEmpty = crl.getRevokedCertificates() == null || crl.getRevokedCertificates().isEmpty(); + boolean isExpired = crl.getNextUpdate().before(now); + if (!isEmpty || options.isProcessEmptyCRLs()) { + if (!isExpired || options.isProcessExpiredCRLs()) { + storeMaterial.add(crl); + if (log.isTraceEnabled()) { + log.trace("Added X509CRL to cert store from issuer {} dated {}", + x500DNHandler.getName(crl.getIssuerX500Principal()), crl.getThisUpdate()); + if (isEmpty) { + log.trace("X509CRL added to cert store from issuer {} dated {} was empty", + x500DNHandler.getName(crl.getIssuerX500Principal()), crl.getThisUpdate()); + } + } + if (isExpired) { + log.warn("Using X509CRL from issuer {} with a nextUpdate in the past: {}", + x500DNHandler.getName(crl.getIssuerX500Principal()), crl.getNextUpdate()); + } + } else { + if (log.isTraceEnabled()) { + log.trace("Expired X509CRL not added to cert store, from issuer {} nextUpdate {}", + x500DNHandler.getName(crl.getIssuerX500Principal()), crl.getNextUpdate()); + } + } + } else { + if (log.isTraceEnabled()) { + log.trace("Empty X509CRL not added to cert store, from issuer {} dated {}", + x500DNHandler.getName(crl.getIssuerX500Principal()), crl.getThisUpdate()); + } + } + } + } + + /** + * Log information from the constructed cert path at level debug. + * + * @param buildResult the PKIX cert path builder result containing the cert path and trust anchor + * @param targetCert the cert untrusted certificate that was being evaluated + */ + private void logCertPathDebug(PKIXCertPathBuilderResult buildResult, X509Certificate targetCert) { + log.debug("Built valid PKIX cert path"); + log.debug("Target certificate: {}", x500DNHandler.getName(targetCert.getSubjectX500Principal())); + for (Certificate cert : buildResult.getCertPath().getCertificates()) { + log.debug("CertPath certificate: {}", x500DNHandler.getName(((X509Certificate) cert) + .getSubjectX500Principal())); + } + TrustAnchor ta = buildResult.getTrustAnchor(); + if (ta.getTrustedCert() != null) { + log.debug("TrustAnchor: {}", x500DNHandler.getName(ta.getTrustedCert().getSubjectX500Principal())); + } else if (ta.getCA() != null) { + log.debug("TrustAnchor: {}", x500DNHandler.getName(ta.getCA())); + } else { + log.debug("TrustAnchor: {}", ta.getCAName()); + } + } + +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/security/x509/CertPathPKIXValidationOptions.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/security/x509/CertPathPKIXValidationOptions.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/security/x509/CertPathPKIXValidationOptions.java 17 Aug 2012 15:16:59 -0000 1.1 @@ -0,0 +1,92 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.security.x509; + +/** + * Specialization of {@link PKIXValidationOptions} which specifies options specific to a {@link PKIXTrustEvaluator} + * based on the Java CertPath API. + */ +public class CertPathPKIXValidationOptions extends PKIXValidationOptions { + + /** Force RevocationEnabled flag. */ + private boolean forceRevocationEnabled; + + /** Value for RevocationEnabled when forced. */ + private boolean revocationEnabled; + + /** Constructor. */ + public CertPathPKIXValidationOptions() { + super(); + forceRevocationEnabled = false; + revocationEnabled = true; + } + + /** + * If true, the revocation behavior of the underlying CertPath provider will be forced to the + * value supplied by {@link #isRevocationEnabled()}. If false, the revocation behavior + * of the underlying provider will be determined by the PKIXTrustEvaluator implementation. + * + *

Default is: false

+ * + * @return Returns the forceRevocationEnabled. + */ + public boolean isForceRevocationEnabled() { + return forceRevocationEnabled; + } + + /** + * If true, the revocation behavior of the underlying CertPath provider will be forced to the + * value supplied by {@link #isRevocationEnabled()}. If false, the revocation behavior + * of the underlying provider will be determined by the PKIXTrustEvaluator implementation. + * + *

Default is: false

+ * + * @param forceRevocationEnabled The forceRevocationEnabled to set. + */ + public void setForceRevocationEnabled(boolean forceRevocationEnabled) { + this.forceRevocationEnabled = forceRevocationEnabled; + } + + /** + * If {@link #isForceRevocationEnabled()} is true, the revocation behavior of the underlying CertPath Provider + * will be forced to this value. If the former is false, the revocation behavior + * of the underlying provider will be determined by the PKIXTrustEvaluator implementation. + * + *

Default is: true

+ * + * @return Returns the revocationEnabled. + */ + public boolean isRevocationEnabled() { + return revocationEnabled; + } + + /** + * If {@link #isForceRevocationEnabled()} is true, the revocation behavior of the underlying CertPath Provider + * will be forced to this value. If the former is false, the revocation behavior + * of the underlying provider will be determined by the PKIXTrustEvaluator implementation. + * + *

Default is: true

+ * + * @param revocationEnabled The revocationEnabled to set. + */ + public void setRevocationEnabled(boolean revocationEnabled) { + this.revocationEnabled = revocationEnabled; + } + + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/security/x509/InternalX500DNHandler.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/security/x509/InternalX500DNHandler.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/security/x509/InternalX500DNHandler.java 17 Aug 2012 15:17:00 -0000 1.1 @@ -0,0 +1,74 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.security.x509; + +import javax.security.auth.x500.X500Principal; + +/** + * Basic implementation of {@link X500DNHandler} which uses the internal built-in mechanisms + * provided by {@link X500Principal} directly. + */ +public class InternalX500DNHandler implements X500DNHandler { + + /** {@inheritDoc} */ + public byte[] getEncoded(X500Principal principal) { + if (principal == null) { + throw new NullPointerException("X500Principal may not be null"); + } + return principal.getEncoded(); + } + + /** {@inheritDoc} */ + public String getName(X500Principal principal) { + if (principal == null) { + throw new NullPointerException("X500Principal may not be null"); + } + return principal.getName(); + } + + /** {@inheritDoc} */ + public String getName(X500Principal principal, String format) { + if (principal == null) { + throw new NullPointerException("X500Principal may not be null"); + } + return principal.getName(format); + } + + /** {@inheritDoc} */ + public X500Principal parse(String name) { + if (name == null) { + throw new NullPointerException("X.500 name string may not be null"); + } + return new X500Principal(name); + } + + /** {@inheritDoc} */ + public X500Principal parse(byte[] name) { + if (name == null) { + throw new NullPointerException("X.500 DER-encoded name may not be null"); + } + return new X500Principal(name); + } + + /** {@inheritDoc} */ + public X500DNHandler clone() { + // We don't have any state, just return a new instance to maintain the clone() contract. + return new InternalX500DNHandler(); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/security/x509/KeyStoreX509CredentialAdapter.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/security/x509/KeyStoreX509CredentialAdapter.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/security/x509/KeyStoreX509CredentialAdapter.java 17 Aug 2012 15:17:00 -0000 1.1 @@ -0,0 +1,111 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.security.x509; + +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.cert.Certificate; +import java.security.cert.X509CRL; +import java.security.cert.X509Certificate; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +import org.opensaml.xml.security.credential.BasicCredential; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** A wrapper that changes a {@link KeyStore} in to a {@link X509Credential}. */ +public class KeyStoreX509CredentialAdapter extends BasicCredential implements X509Credential { + + /** Class logger. */ + private Logger log = LoggerFactory.getLogger(KeyStoreX509CredentialAdapter.class); + + /** Keystore that contains the credential to be exposed. */ + private KeyStore keyStore; + + /** Alias to the credential to be exposed. */ + private String credentialAlias; + + /** Password for the key to be exposed. */ + private char[] keyPassword; + + /** + * Constructor. + * + * @param store store containing key to be exposed + * @param alias alias to the credential to be exposed + * @param password password to the key to be exposed + */ + public KeyStoreX509CredentialAdapter(KeyStore store, String alias, char[] password) { + keyStore = store; + credentialAlias = alias; + keyPassword = password; + } + + /** {@inheritDoc} */ + public Collection getCRLs() { + return Collections.EMPTY_LIST; + } + + /** {@inheritDoc} */ + public X509Certificate getEntityCertificate() { + try { + return (X509Certificate) keyStore.getCertificate(credentialAlias); + } catch (KeyStoreException e) { + log.error("Error accessing {} certificates in keystore", e); + return null; + } + } + + /** {@inheritDoc} */ + public Collection getEntityCertificateChain() { + List certsCollection = Collections.EMPTY_LIST; + + try { + Certificate[] certs = keyStore.getCertificateChain(credentialAlias); + if (certs != null) { + certsCollection = new ArrayList(certs.length); + for (Certificate cert : certs) { + certsCollection.add((X509Certificate) cert); + } + } + } catch (KeyStoreException e) { + log.error("Error accessing {} certificates in keystore", e); + } + return certsCollection; + } + + /** {@inheritDoc} */ + public PrivateKey getPrivateKey() { + try { + return (PrivateKey) keyStore.getKey(credentialAlias, keyPassword); + } catch (Exception e) { + log.error("Error accessing {} private key in keystore", e); + return null; + } + } + + /** {@inheritDoc} */ + public PublicKey getPublicKey() { + return getEntityCertificate().getPublicKey(); + } +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/security/x509/PKIXTrustEngine.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/security/x509/PKIXTrustEngine.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/security/x509/PKIXTrustEngine.java 17 Aug 2012 15:16:59 -0000 1.1 @@ -0,0 +1,36 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.security.x509; + +import org.opensaml.xml.security.trust.TrustEngine; + +/** + * Trust engine that validates tokens using PKIX validation. + * + * @param the token type this trust engine evaluates + */ +public interface PKIXTrustEngine extends TrustEngine { + + /** + * Get the resolver instance which will be used to resolve PKIX validation information. + * + * @return the currently configured resolver instance + */ + public PKIXValidationInformationResolver getPKIXResolver(); + +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/security/x509/PKIXTrustEvaluator.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/security/x509/PKIXTrustEvaluator.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/security/x509/PKIXTrustEvaluator.java 17 Aug 2012 15:17:00 -0000 1.1 @@ -0,0 +1,48 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.security.x509; + +import org.opensaml.xml.security.SecurityException; + +/** + * An interface for classes which evaluate an {@link X509Credential} against a set of trusted + * {@link PKIXValidationInformation}, using PKIX validation rules. + */ +public interface PKIXTrustEvaluator { + + /** + * Validate the specified credential against the specified set of trusted validation information. + * + * @param validationInfo the set of trusted validation information + * @param untrustedCredential the credential being evaluated + * @return true if the credential can be successfully evaluated, false otherwise + * @throws SecurityException thrown if there is an error evaluating the credential + */ + public boolean validate(PKIXValidationInformation validationInfo, X509Credential untrustedCredential) + throws SecurityException; + + /** + * Get the {@link PKIXValidationOptions} instance that is in use. + * + * @return the PKIXValidationOptions instance + */ + public PKIXValidationOptions getPKIXValidationOptions(); + +} + + Index: 3rdParty_sources/xmltooling/org/opensaml/xml/security/x509/PKIXValidationInformation.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/security/x509/PKIXValidationInformation.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/security/x509/PKIXValidationInformation.java 17 Aug 2012 15:16:59 -0000 1.1 @@ -0,0 +1,49 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.security.x509; + +import java.security.cert.X509CRL; +import java.security.cert.X509Certificate; +import java.util.Collection; + +/** + * Source of PKIX validation information such as trust anchors and CRLs. + */ +public interface PKIXValidationInformation { + + /** + * Gets the maximum allowable trust chain verification depth. + * + * @return maximum allowable trust chain verification depth + */ + public Integer getVerificationDepth(); + + /** + * Gets the certificate trust anchors used during PKIX validation. + * + * @return trust anchors used during PKIX validation + */ + public Collection getCertificates(); + + /** + * Gets the CRLs used during PKIX validation. + * + * @return CRLs used during PKIX validation + */ + public Collection getCRLs(); +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/security/x509/PKIXValidationInformationResolver.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/security/x509/PKIXValidationInformationResolver.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/security/x509/PKIXValidationInformationResolver.java 17 Aug 2012 15:16:59 -0000 1.1 @@ -0,0 +1,57 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.security.x509; + +import java.util.Set; + +import org.opensaml.xml.security.Criteria; +import org.opensaml.xml.security.CriteriaSet; +import org.opensaml.xml.security.Resolver; +import org.opensaml.xml.security.SecurityException; + +/** + * A resolver which uses {@link Criteria} to resolve {@link PKIXValidationInformation}, which will typically be used + * PKIX-based trust engines. + * + * Implementations may also optionally implement {@link #resolveTrustedNames(CriteriaSet)}, which will + * return a set of trusted names associated with the entity implied by the criteria. These trusted names + * may be used to validate (in an application-specific manner) that an entity is trusted to wield a particular + * certificate. + */ +public interface PKIXValidationInformationResolver extends Resolver { + + /** + * Resolve a set of trusted names associated with the entity indicated by the criteria. This method + * is optional to implement. + * + * @param criteriaSet set of criteria used to determine or resolve the trusted names + * @return the set of certificate names trusted for an entity + * @throws SecurityException thrown if there is an error resolving the trusted names + * @throws UnsupportedOperationException thrown if this optional method is not supported by the implementation + */ + public Set resolveTrustedNames(CriteriaSet criteriaSet) + throws SecurityException, UnsupportedOperationException; + + /** + * Check whether resolution of trusted names is supported. + * + * @return true if the implementation supports resolution of trusted names, otherwise false + */ + public boolean supportsTrustedNameResolution(); + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/security/x509/PKIXValidationOptions.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/security/x509/PKIXValidationOptions.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/security/x509/PKIXValidationOptions.java 17 Aug 2012 15:17:00 -0000 1.1 @@ -0,0 +1,139 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.security.x509; + +/** + * Options which may be supplied to influence the processing behavior of a {@link PKIXTrustEvaluator}. + */ +public class PKIXValidationOptions { + + /** Flag as to whether empty CRL's will be processed. */ + private boolean processEmptyCRLs; + + /** Flag as to whether expired CRL's will be processed. */ + private boolean processExpiredCRLs; + + /** Flag as to whether CRL's supplied in the untrusted credential being evaluated will be processed. */ + private boolean processCredentialCRLs; + + /** Default verification depth. */ + private Integer defaultVerificationDepth; + + /** Constructor. */ + public PKIXValidationOptions() { + processEmptyCRLs = true; + processExpiredCRLs = true; + processCredentialCRLs = true; + + defaultVerificationDepth = new Integer(1); + } + + /** + * Whether empty CRL's should be processed. + * + *

Default is: true

+ * + * @return Returns the processEmptyCRLs. + */ + public boolean isProcessEmptyCRLs() { + return processEmptyCRLs; + } + + /** + * Whether empty CRL's should be processed. + * + *

Default is: true

+ * + * @param processEmptyCRLs The processEmptyCRLs to set. + */ + public void setProcessEmptyCRLs(boolean processEmptyCRLs) { + this.processEmptyCRLs = processEmptyCRLs; + } + + /** + * Whether expired CRL's should be processed. + * + *

Default is: true

+ * + * @return Returns the processExpiredCRLs. + */ + public boolean isProcessExpiredCRLs() { + return processExpiredCRLs; + } + + /** + * Whether expired CRL's should be processed. + * + *

Default is: true

+ * + * @param processExpiredCRLs The processExpiredCRLs to set. + */ + public void setProcessExpiredCRLs(boolean processExpiredCRLs) { + this.processExpiredCRLs = processExpiredCRLs; + } + + /** + * Whether CRL's supplied within the untrusted {@link X509Credential} being evaluated should be processed. + * + *

Default is: true

+ * + * @return Returns the processCredentialCRLs. + */ + public boolean isProcessCredentialCRLs() { + return processCredentialCRLs; + } + + /** + * Whether CRL's supplied within the untrusted {@link X509Credential} being evaluated should be processed. + * + *

Default is: true

+ * + * @param processCredentialCRLs The processCredentialCRLs to set. + */ + public void setProcessCredentialCRLs(boolean processCredentialCRLs) { + this.processCredentialCRLs = processCredentialCRLs; + } + + /** + * The default PKIX maximum path verification depth, if not supplied in the + * {@link PKIXValidationInformation} being evaluated. + * + *

Default is: 1

+ * + * @return Returns the defaultVerificationDepth. + */ + public Integer getDefaultVerificationDepth() { + return defaultVerificationDepth; + } + + /** + * The default PKIX maximum path verification depth, if not supplied in the + * {@link PKIXValidationInformation} being evaluated. + * + *

Default is: 1

+ * + * @param defaultVerificationDepth The defaultVerificationDepth to set. + */ + public void setDefaultVerificationDepth(Integer defaultVerificationDepth) { + if (defaultVerificationDepth == null) { + throw new IllegalArgumentException("Default verification depth may not be null"); + } + this.defaultVerificationDepth = defaultVerificationDepth; + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/security/x509/PKIXX509CredentialTrustEngine.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/security/x509/PKIXX509CredentialTrustEngine.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/security/x509/PKIXX509CredentialTrustEngine.java 17 Aug 2012 15:16:59 -0000 1.1 @@ -0,0 +1,201 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.security.x509; + +import java.util.Set; + +import org.opensaml.xml.security.CriteriaSet; +import org.opensaml.xml.security.SecurityException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Trust engine implementation which evaluates an X509Credential token based on PKIX validation processing using + * validation information from a trusted source. + * + */ +public class PKIXX509CredentialTrustEngine implements PKIXTrustEngine { + + /** Class logger. */ + private final Logger log = LoggerFactory.getLogger(PKIXX509CredentialTrustEngine.class); + + /** Resolver used for resolving trusted credentials. */ + private PKIXValidationInformationResolver pkixResolver; + + /** The external PKIX trust evaluator used to establish trust. */ + private PKIXTrustEvaluator pkixTrustEvaluator; + + /** The external credential name evaluator used to establish trusted name compliance. */ + private X509CredentialNameEvaluator credNameEvaluator; + + /** + * Constructor. + * + *

The PKIX trust evaluator used defaults to {@link CertPathPKIXTrustEvaluator}.

+ * + *

The X.509 credential name evaluator used defaults to {@link BasicX509CredentialNameEvaluator}.

+ * + * @param resolver credential resolver used to resolve trusted credentials + */ + public PKIXX509CredentialTrustEngine(PKIXValidationInformationResolver resolver) { + if (resolver == null) { + throw new IllegalArgumentException("PKIX trust information resolver may not be null"); + } + pkixResolver = resolver; + + pkixTrustEvaluator = new CertPathPKIXTrustEvaluator(); + credNameEvaluator = new BasicX509CredentialNameEvaluator(); + } + + /** + * Constructor. + * + * @param resolver credential resolver used to resolve trusted credentials + * @param pkixEvaluator the PKIX trust evaluator to use + * @param nameEvaluator the X.509 credential name evaluator to use (may be null) + */ + public PKIXX509CredentialTrustEngine(PKIXValidationInformationResolver resolver, PKIXTrustEvaluator pkixEvaluator, + X509CredentialNameEvaluator nameEvaluator) { + if (resolver == null) { + throw new IllegalArgumentException("PKIX trust information resolver may not be null"); + } + pkixResolver = resolver; + + if (pkixEvaluator == null) { + throw new IllegalArgumentException("PKIX trust evaluator may not be null"); + } + pkixTrustEvaluator = pkixEvaluator; + credNameEvaluator = nameEvaluator; + } + + /** {@inheritDoc} */ + public PKIXValidationInformationResolver getPKIXResolver() { + return pkixResolver; + } + + /** + * Get the PKIXTrustEvaluator instance used to evalute trust. + * + *

The parameters of this evaluator may be modified to + * adjust trust evaluation processing.

+ * + * @return the PKIX trust evaluator instance that will be used + */ + public PKIXTrustEvaluator getPKIXTrustEvaluator() { + return pkixTrustEvaluator; + } + + /** + * Get the X509CredentialNameEvaluator instance used to evalute a credential + * against trusted names. + * + *

The parameters of this evaluator may be modified to + * adjust trust evaluation processing.

+ * + * @return the PKIX trust evaluator instance that will be used + */ + public X509CredentialNameEvaluator getX509CredentialNameEvaluator() { + return credNameEvaluator; + } + + /** {@inheritDoc} */ + public boolean validate(X509Credential untrustedCredential, CriteriaSet trustBasisCriteria) + throws SecurityException { + + log.debug("Attempting PKIX validation of untrusted credential"); + + if (untrustedCredential == null) { + log.error("X.509 credential was null, unable to perform validation"); + return false; + } + + if (untrustedCredential.getEntityCertificate() == null) { + log.error("Untrusted X.509 credential's entity certificate was null, unable to perform validation"); + return false; + } + + Set trustedNames = null; + if (pkixResolver.supportsTrustedNameResolution()) { + trustedNames = pkixResolver.resolveTrustedNames(trustBasisCriteria); + } else { + log.debug("PKIX resolver does not support resolution of trusted names, skipping name checking"); + } + + return validate(untrustedCredential, trustedNames, pkixResolver.resolve(trustBasisCriteria)); + } + + /** + * Perform PKIX validation on the untrusted credential, using PKIX validation information based on the supplied set + * of trusted credentials. + * + * @param untrustedX509Credential the credential to evaluate + * @param validationInfoSet the set of validation information which serves as ths basis for trust evaluation + * @param trustedNames the set of trusted names for name checking purposes + * + * @return true if PKIX validation of the untrusted credential is successful, otherwise false + * @throws SecurityException thrown if there is an error validating the untrusted credential + * against trusted names or validation information + */ + protected boolean validate(X509Credential untrustedX509Credential, Set trustedNames, + Iterable validationInfoSet) throws SecurityException { + + log.debug("Beginning PKIX validation using trusted validation information"); + + if (!checkNames(trustedNames, untrustedX509Credential)) { + log.debug("Evaluation of credential against trusted names failed. Aborting PKIX validation"); + return false; + } + + for (PKIXValidationInformation validationInfo : validationInfoSet) { + try { + if (pkixTrustEvaluator.validate(validationInfo, untrustedX509Credential)) { + log.debug("Credential trust established via PKIX validation"); + return true; + } + } catch (SecurityException e) { + // log the operational error, but allow other validation info sets to be tried + log.debug("Error performing PKIX validation on untrusted credential", e); + } + } + log.debug("Trust of untrusted credential could not be established via PKIX validation"); + return false; + } + + /** + * Evaluate the credential against the set of trusted names. + * + *

Evaluates to true if no intsance of {@link X509CredentialNameEvaluator} is configured.

+ * + * @param trustedNames set of trusted names + * @param untrustedCredential the credential being evaluated + * @return true if evaluation is successful, false otherwise + * @throws SecurityException thrown if there is an error evaluation the credential + */ + protected boolean checkNames(Set trustedNames, X509Credential untrustedCredential) + throws SecurityException { + + if (credNameEvaluator == null) { + log.debug("No credential name evaluator was available, skipping trusted name evaluation"); + return true; + } else { + return credNameEvaluator.evaluate(untrustedCredential, trustedNames); + } + + } + +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/security/x509/StaticPKIXValidationInformationResolver.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/security/x509/StaticPKIXValidationInformationResolver.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/security/x509/StaticPKIXValidationInformationResolver.java 17 Aug 2012 15:16:59 -0000 1.1 @@ -0,0 +1,86 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.security.x509; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.opensaml.xml.security.CriteriaSet; +import org.opensaml.xml.security.SecurityException; + +/** + * An implementation of {@link PKIXValidationInformationResolver} which always returns a static, fixed set of + * information. + */ +public class StaticPKIXValidationInformationResolver implements PKIXValidationInformationResolver { + + /** The PKIX validation information to return. */ + private List pkixInfo; + + /** The set of trusted names to return. */ + private Set trustedNames; + + /** + * Constructor. + * + * @param info list of PKIX validation information to return + * @param names set of trusted names to return + */ + public StaticPKIXValidationInformationResolver(List info, Set names) { + if (info != null) { + pkixInfo = new ArrayList(info); + } else { + pkixInfo = Collections.EMPTY_LIST; + } + + if (names != null) { + trustedNames = new HashSet(names); + } else { + trustedNames = Collections.EMPTY_SET; + } + } + + /** {@inheritDoc} */ + public Set resolveTrustedNames(CriteriaSet criteriaSet) throws SecurityException, + UnsupportedOperationException { + + return trustedNames; + } + + /** {@inheritDoc} */ + public boolean supportsTrustedNameResolution() { + return true; + } + + /** {@inheritDoc} */ + public Iterable resolve(CriteriaSet criteria) throws SecurityException { + return pkixInfo; + } + + /** {@inheritDoc} */ + public PKIXValidationInformation resolveSingle(CriteriaSet criteria) throws SecurityException { + if (!pkixInfo.isEmpty()) { + return pkixInfo.get(0); + } + return null; + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/security/x509/X500DNHandler.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/security/x509/X500DNHandler.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/security/x509/X500DNHandler.java 17 Aug 2012 15:17:00 -0000 1.1 @@ -0,0 +1,93 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.security.x509; + +import javax.security.auth.x500.X500Principal; + +/** + * Interface for implementations which handle parsing and serialization of X.500 names + * represented by {@link X500Principal}. + */ +public interface X500DNHandler { + + /** Specifies the string format specified in RFC 1779. */ + public static final String FORMAT_RFC1779 = X500Principal.RFC1779; + + /** Specifies the string format specified in RFC 2253. */ + public static final String FORMAT_RFC2253 = X500Principal.RFC2253; + + /** + * Parse the string representation of a name and build a new principal instance. + * + * @param name the name string to parse + * @return a new principal instance + * + * @throws IllegalArgumentException if the name value can not be parsed by the implementation + */ + public X500Principal parse(String name); + + /** + * Parse the ASN.1 DER encoding representation of a name and build a new principal instance. + * + * @param name a distinguished name in ASN.1 DER encoded form + * @return a new principal instance + * + * @throws IllegalArgumentException if the name value can not be parsed by the implementation + */ + public X500Principal parse(byte[] name); + + /** + * Returns a string representation of the X.500 distinguished name using the default format + * as defined in the underlying implementation. + * + * @param principal the principal name instance to serialize + * @return the serialized string name + */ + public String getName(X500Principal principal); + + /** + * Returns a string representation of the X.500 distinguished name using the specified format. + * + * The values and meanings of the format specifier are implementation dependent. Constants for + * two common standard formats are provided here as {@link #FORMAT_RFC1779} and {@link #FORMAT_RFC2253}; + * + * @param principal the principal name instance to serialize + * @param format the format specifier of the resulting serialized string name + * @return the serialized string name + * + * @throws IllegalArgumentException if the specified format is not understood by the implementation + */ + public String getName(X500Principal principal, String format); + + /** + * Returns the distinguished name in ASN.1 DER encoded form. + * + * @param principal the principal name instance to serialize + * @return the serialized name in ASN.1 DER encoded form + */ + public byte[] getEncoded(X500Principal principal); + + /** + * Clone the handler. Implementations which maintain instance-specific configuration data, etc, + * should implement this appropriately, possibly also implementing {@link Cloneable}. + * + * @return the cloned handler + */ + public X500DNHandler clone(); + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/security/x509/X509Credential.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/security/x509/X509Credential.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/security/x509/X509Credential.java 17 Aug 2012 15:16:59 -0000 1.1 @@ -0,0 +1,57 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.security.x509; + +import java.security.cert.X509CRL; +import java.security.cert.X509Certificate; +import java.util.Collection; + +import org.opensaml.xml.security.credential.Credential; + +/** + * An entity credential based on key material and other information (e.g. certificates and certificate + * revocation lists) associated with X.509 Public Key Infrastructure. + * + * Note that this type of credential may not contain a symmetric (secret) key, and hence + * {@link Credential#getSecretKey()} should always return null. + */ +public interface X509Credential extends Credential { + + /** + * Gets the public certificate for the entity. The public key of this certificate will be + * the same key obtained from {@link Credential#getPublicKey()}. + * + * @return the public certificate for the entity + */ + public X509Certificate getEntityCertificate(); + + /** + * Gets an immutable collection of certificates in the entity's trust chain. The entity certificate is contained + * within this list. No specific ordering of the certificates is guaranteed. + * + * @return entities certificate chain + */ + public Collection getEntityCertificateChain(); + + /** + * Gets a collection of CRLs associated with the credential. + * + * @return CRLs associated with the credential + */ + public Collection getCRLs(); +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/security/x509/X509CredentialNameEvaluator.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/security/x509/X509CredentialNameEvaluator.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/security/x509/X509CredentialNameEvaluator.java 17 Aug 2012 15:16:59 -0000 1.1 @@ -0,0 +1,45 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.security.x509; + +import java.util.Set; + +import org.opensaml.xml.security.SecurityException; + +/** + * Interface for classes which evaluate an {@link X509Credential} against a + * supplied set of trusted names. + */ +public interface X509CredentialNameEvaluator { + + /** + * Evaluate the specified credential against the specified set of trusted names. + * + *

The types of names supported, and the manner in which they are evaluated, is + * implementation-specific.

+ * + * @param credential the X.509 credential to evaluate + * @param trustedNames trusted names against which the credential will be evaluated + * + * @return true if the name evaluation succeeds, false otherwise + * + * @throws SecurityException thrown if there is an error during name evaluation + */ + public boolean evaluate(X509Credential credential, Set trustedNames) throws SecurityException; + +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/security/x509/X509IssuerSerialCriteria.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/security/x509/X509IssuerSerialCriteria.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/security/x509/X509IssuerSerialCriteria.java 17 Aug 2012 15:16:59 -0000 1.1 @@ -0,0 +1,90 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.security.x509; + +import java.math.BigInteger; + +import javax.security.auth.x500.X500Principal; + +import org.opensaml.xml.security.Criteria; + +/** + * An implementation of {@link Criteria} which specifies criteria based on + * X.509 certificate issuer name and serial number. + */ +public final class X509IssuerSerialCriteria implements Criteria { + + /** X.509 certificate issuer name. */ + private X500Principal issuerName; + + /** X.509 certificate serial number. */ + private BigInteger serialNumber; + + /** + * Constructor. + * + * @param issuer certificate issuer name + * @param serial certificate serial number + */ + public X509IssuerSerialCriteria(X500Principal issuer, BigInteger serial) { + setIssuerName(issuer); + setSerialNumber(serial); + } + + /** Get the issuer name. + * + * @return Returns the issuer name. + */ + public X500Principal getIssuerName() { + return issuerName; + } + + /** + * Set the issuer name. + * + * @param issuer The issuer name to set. + */ + public void setIssuerName(X500Principal issuer) { + if (issuer == null) { + throw new IllegalArgumentException("Issuer principal criteria value may not be null"); + } + this.issuerName = issuer; + } + + /** + * Get the serial number. + * + * @return Returns the serial number. + */ + public BigInteger getSerialNumber() { + return serialNumber; + } + + /** + * Set the serial number. + * + * @param serial The serial number to set. + */ + public void setSerialNumber(BigInteger serial) { + if (serial == null) { + throw new IllegalArgumentException("Serial number criteria value may not be null"); + } + this.serialNumber = serial; + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/security/x509/X509KeyInfoGeneratorFactory.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/security/x509/X509KeyInfoGeneratorFactory.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/security/x509/X509KeyInfoGeneratorFactory.java 17 Aug 2012 15:16:59 -0000 1.1 @@ -0,0 +1,721 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.security.x509; + +import java.security.cert.CRLException; +import java.security.cert.CertificateEncodingException; +import java.util.List; +import java.util.Set; + +import javax.security.auth.x500.X500Principal; + +import org.opensaml.xml.Configuration; +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.security.SecurityException; +import org.opensaml.xml.security.credential.BasicKeyInfoGeneratorFactory; +import org.opensaml.xml.security.credential.Credential; +import org.opensaml.xml.security.keyinfo.KeyInfoGenerator; +import org.opensaml.xml.security.keyinfo.KeyInfoHelper; +import org.opensaml.xml.signature.KeyInfo; +import org.opensaml.xml.signature.X509CRL; +import org.opensaml.xml.signature.X509Certificate; +import org.opensaml.xml.signature.X509Data; +import org.opensaml.xml.signature.X509SKI; +import org.opensaml.xml.signature.impl.KeyInfoBuilder; +import org.opensaml.xml.signature.impl.X509DataBuilder; +import org.opensaml.xml.util.DatatypeHelper; +import org.opensaml.xml.util.LazySet; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * A factory implementation which produces instances of {@link KeyInfoGenerator} capable of + * handling the information contained within an {@link X509Credential}. + * + * All boolean options default to false. The default implementation of {@link X500DNHandler} used is + * {@link InternalX500DNHandler}. The default output format for subject and issuer DN's is RFC2253. + * The default set of subject alternative names to process is empty. + */ +public class X509KeyInfoGeneratorFactory extends BasicKeyInfoGeneratorFactory { + + /** The set of options configured for the factory. */ + private X509Options options; + + /** Constructor. */ + public X509KeyInfoGeneratorFactory() { + super(); + options = (X509Options) super.getOptions(); + } + + /** {@inheritDoc} */ + public Class getCredentialType() { + return X509Credential.class; + } + + /** {@inheritDoc} */ + public boolean handles(Credential credential) { + return credential instanceof X509Credential; + } + + /** {@inheritDoc} */ + public KeyInfoGenerator newInstance() { + //TODO lock options during cloning ? + X509Options newOptions = options.clone(); + return new X509KeyInfoGenerator(newOptions); + } + + /** + * Get the option to emit the CRL list as sequence of X509CRL elements within X509Data. + * + * @return the option value + */ + public boolean emitCRLs() { + return options.emitCRLs; + } + + /** + * Set the option to emit the CRL list as sequence of X509CRL elements within X509Data. + * + * @param newValue the new option value + */ + public void setEmitCRLs(boolean newValue) { + options.emitCRLs = newValue; + } + + /** + * Get the option to emit the entity certificate as an X509Certificate element within X509Data. + * + * @return the option value + */ + public boolean emitEntityCertificate() { + return options.emitEntityCertificate; + } + + /** + * Set the option to emit the entity certificate as an X509Certificate element within X509Data. + * + * @param newValue the new option value + */ + public void setEmitEntityCertificate(boolean newValue) { + options.emitEntityCertificate = newValue; + } + + /** + * Get the option to emit the entity certificate chain as sequence of X509Certificate elements within X509Data. + * + * @return the option value + */ + public boolean emitEntityCertificateChain() { + return options.emitEntityCertificateChain; + } + + /** + * Set the option to emit the entity certificate chain as sequence of X509Certificate elements within X509Data. + * + * @param newValue the new option value + */ + public void setEmitEntityCertificateChain(boolean newValue) { + options.emitEntityCertificateChain = newValue; + } + + /** + * Get the option to emit the entity certificate subject alternative name extension values as KeyName elements. + * + * @return the option value + */ + public boolean emitSubjectAltNamesAsKeyNames() { + return options.emitSubjectAltNamesAsKeyNames; + } + + /** + * Set the option to emit the entity certificate subject alternative name extension values as KeyName elements. + * + * @param newValue the new option value + */ + public void setEmitSubjectAltNamesAsKeyNames(boolean newValue) { + options.emitSubjectAltNamesAsKeyNames = newValue; + } + + /** + * Get the option to emit the entity certificate subject DN common name (CN) fields as KeyName elements. + * + * @return the option value + */ + public boolean emitSubjectCNAsKeyName() { + return options.emitSubjectCNAsKeyName; + } + + /** + * Set the option to emit the entity certificate subject DN common name (CN) fields as KeyName elements. + * + * @param newValue the new option value + */ + public void setEmitSubjectCNAsKeyName(boolean newValue) { + options.emitSubjectCNAsKeyName = newValue; + } + + /** + * Get the option to emit the entity certificate subject DN as a KeyName element. + * + * @return the option value + */ + public boolean emitSubjectDNAsKeyName() { + return options.emitSubjectDNAsKeyName; + } + + /** + * Set the option to emit the entity certificate subject DN as a KeyName element. + * + * @param newValue the new option value + */ + public void setEmitSubjectDNAsKeyName(boolean newValue) { + options.emitSubjectDNAsKeyName = newValue; + } + + /** + * Get the option to emit the entity certificate issuer name and serial number as + * an X509IssuerSerial element within X509Data. + * + * @return the option value + */ + public boolean emitX509IssuerSerial() { + return options.emitX509IssuerSerial; + } + + /** + * Set the option to emit the entity certificate issuer name and serial number as + * an X509IssuerSerial element within X509Data. + * + * @param newValue the new option value + */ + public void setEmitX509IssuerSerial(boolean newValue) { + options.emitX509IssuerSerial = newValue; + } + + /** + * Get the option to emit the entity certificate subject key identifier as an X509SKI element within X509Data. + * + * @return the option value + */ + public boolean emitX509SKI() { + return options.emitX509SKI; + } + + /** + * Set the option to emit the entity certificate subject key identifier as an X509SKI element within X509Data. + * + * @param newValue the new option value + */ + public void setEmitX509SKI(boolean newValue) { + options.emitX509SKI = newValue; + } + + /** + * Get the option to emit the entity certificate subject DN as an X509SubjectName element within X509Data. + * + * @return the option value + */ + public boolean emitX509SubjectName() { + return options.emitX509SubjectName; + } + + /** + * Set the option to emit the entity certificate subject DN as an X509SubjectName element within X509Data. + * + * @param newValue the new option value + */ + public void setEmitX509SubjectName(boolean newValue) { + options.emitX509SubjectName = newValue; + } + + /** + * The set of types of subject alternative names to process. + * + * Name types are represented using the constant OID tag name values defined + * in {@link X509Util}. + * + * + * @return the modifiable set of alt name identifiers + */ + public Set getSubjectAltNames() { + return options.subjectAltNames; + } + + /** + * Get the handler which process X.500 distinguished names. + * + * Defaults to {@link InternalX500DNHandler}. + * + * @return returns the X500DNHandler instance + */ + public X500DNHandler getX500DNHandler() { + return options.x500DNHandler; + } + + /** + * Set the handler which process X.500 distinguished names. + * + * Defaults to {@link InternalX500DNHandler}. + * + * @param handler the new X500DNHandler instance + */ + public void setX500DNHandler(X500DNHandler handler) { + if (handler == null) { + throw new IllegalArgumentException("X500DNHandler may not be null"); + } + options.x500DNHandler = handler; + } + + /** + * Get the output format specifier for X.500 subject names. + * + * Defaults to RFC2253 format. The meaning of this format specifier value + * is dependent upon the implementation of {@link X500DNHandler} which is used. + * + * @return returns the format specifier + */ + public String getX500SubjectDNFormat() { + return options.x500SubjectDNFormat; + } + + /** + * Set the output format specifier for X.500 subject names. + * + * Defaults to RFC2253 format. The meaning of this format specifier value + * is dependent upon the implementation of {@link X500DNHandler} which is used. + * + * @param format the new X500DNHandler instance + */ + public void setX500SubjectDNFormat(String format) { + options.x500SubjectDNFormat = format; + } + + /** + * Get the output format specifier for X.500 issuer names. + * + * Defaults to RFC2253 format. The meaning of this format specifier value + * is dependent upon the implementation of {@link X500DNHandler} which is used. + * + * @return returns the format specifier + */ + public String getX500IssuerDNFormat() { + return options.x500IssuerDNFormat; + } + + /** + * Set the output format specifier for X.500 issuer names. + * + * Defaults to RFC2253 format. The meaning of this format specifier value + * is dependent upon the implementation of {@link X500DNHandler} which is used. + * + * @param format the new X500DNHandler instance + */ + public void setX500IssuerDNFormat(String format) { + options.x500IssuerDNFormat = format; + } + + /** {@inheritDoc} */ + protected X509Options getOptions() { + return options; + } + + /** {@inheritDoc} */ + protected X509Options newOptions() { + return new X509Options(); + } + + /** + * An implementation of {@link KeyInfoGenerator} capable of handling the information + * contained within a {@link X509Credential}. + */ + public class X509KeyInfoGenerator extends BasicKeyInfoGenerator { + + /** Class logger. */ + private final Logger log = LoggerFactory.getLogger(X509KeyInfoGenerator.class); + + /** The set of options to be used by the generator.*/ + private X509Options options; + + /** Builder for KeyInfo objects. */ + private KeyInfoBuilder keyInfoBuilder; + + /** Builder for X509Data objects. */ + private X509DataBuilder x509DataBuilder; + + /** + * Constructor. + * + * @param newOptions the options to be used by the generator + */ + protected X509KeyInfoGenerator(X509Options newOptions) { + super(newOptions); + options = newOptions; + + keyInfoBuilder = + (KeyInfoBuilder) Configuration.getBuilderFactory().getBuilder(KeyInfo.DEFAULT_ELEMENT_NAME); + x509DataBuilder = + (X509DataBuilder) Configuration.getBuilderFactory().getBuilder(X509Data.DEFAULT_ELEMENT_NAME); + } + + /** {@inheritDoc} */ + public KeyInfo generate(Credential credential) throws SecurityException { + if ( ! (credential instanceof X509Credential) ) { + log.warn("X509KeyInfoGenerator was passed a credential that was not an instance of X509Credential: {}", + credential.getClass().getName()); + return null; + } + X509Credential x509Credential = (X509Credential) credential; + + KeyInfo keyInfo = super.generate(credential); + if (keyInfo == null) { + keyInfo = keyInfoBuilder.buildObject(); + } + X509Data x509Data = x509DataBuilder.buildObject(); + + processEntityCertificate(keyInfo, x509Data, x509Credential); + processEntityCertificateChain(keyInfo, x509Data, x509Credential); + processCRLs(keyInfo, x509Data, x509Credential); + + List x509DataChildren = x509Data.getOrderedChildren(); + if (x509DataChildren != null && x509DataChildren.size() > 0) { + keyInfo.getX509Datas().add(x509Data); + } + + List keyInfoChildren = keyInfo.getOrderedChildren(); + if (keyInfoChildren != null && keyInfoChildren.size() > 0) { + return keyInfo; + } else { + return null; + } + } + + /** Process the value of {@link X509Credential#getEntityCertificate()}. + * + * @param keyInfo the KeyInfo that is being built + * @param x509Data the X509Data that is being built + * @param credential the Credential that is being processed + * @throws SecurityException thrown if the certificate data can not be encoded from the Java certificate object + */ + protected void processEntityCertificate(KeyInfo keyInfo, X509Data x509Data, X509Credential credential) + throws SecurityException { + + if (credential.getEntityCertificate() == null) { + return; + } + + java.security.cert.X509Certificate javaCert = credential.getEntityCertificate(); + + processCertX509DataOptions(x509Data, javaCert); + processCertKeyNameOptions(keyInfo, javaCert); + + // The cert chain includes the entity cert, so don't add a duplicate + if (options.emitEntityCertificate && ! options.emitEntityCertificateChain) { + try { + X509Certificate xmlCert = KeyInfoHelper.buildX509Certificate(javaCert); + x509Data.getX509Certificates().add(xmlCert); + } catch (CertificateEncodingException e) { + throw new SecurityException("Error generating X509Certificate element " + + "from credential's end-entity certificate", e); + } + } + + } + + /** + * Process the options related to generation of child elements of X509Data based on certificate data. + * + * @param x509Data the X509Data element being processed. + * @param cert the certificate being processed + */ + protected void processCertX509DataOptions(X509Data x509Data, java.security.cert.X509Certificate cert) { + processCertX509SubjectName(x509Data, cert); + processCertX509IssuerSerial(x509Data, cert); + processCertX509SKI(x509Data, cert); + } + + /** + * Process the options related to generation of KeyName elements based on certificate data. + * + * @param keyInfo the KeyInfo element being processed. + * @param cert the certificate being processed + */ + protected void processCertKeyNameOptions(KeyInfo keyInfo, java.security.cert.X509Certificate cert) { + processSubjectDNKeyName(keyInfo, cert); + processSubjectCNKeyName(keyInfo, cert); + processSubjectAltNameKeyNames(keyInfo, cert); + } + + /** + * Process the options related to generation of the X509SubjectDN child element of X509Data + * based on certificate data. + * + * @param x509Data the X509Data element being processed. + * @param cert the certificate being processed + */ + protected void processCertX509SubjectName(X509Data x509Data, java.security.cert.X509Certificate cert) { + if (options.emitX509SubjectName) { + String subjectNameValue = getSubjectName(cert); + if (! DatatypeHelper.isEmpty(subjectNameValue)) { + x509Data.getX509SubjectNames().add( KeyInfoHelper.buildX509SubjectName(subjectNameValue)); + } + } + } + + /** + * Process the options related to generation of the X509IssuerSerial child element of X509Data + * based on certificate data. + * + * @param x509Data the X509Data element being processed. + * @param cert the certificate being processed + */ + protected void processCertX509IssuerSerial(X509Data x509Data, java.security.cert.X509Certificate cert) { + if (options.emitX509IssuerSerial) { + String issuerNameValue = getIssuerName(cert); + if (! DatatypeHelper.isEmpty(issuerNameValue)) { + x509Data.getX509IssuerSerials().add( + KeyInfoHelper.buildX509IssuerSerial(issuerNameValue, cert.getSerialNumber()) ); + } + } + } + + /** + * Process the options related to generation of the X509SKI child element of X509Data + * based on certificate data. + * + * @param x509Data the X509Data element being processed. + * @param cert the certificate being processed + */ + protected void processCertX509SKI(X509Data x509Data, java.security.cert.X509Certificate cert) { + if (options.emitX509SKI) { + X509SKI xmlSKI = KeyInfoHelper.buildX509SKI(cert); + if (xmlSKI != null) { + x509Data.getX509SKIs().add(xmlSKI); + } + } + } + + /** + * Get subject name from a certificate, using the currently configured X500DNHandler + * and subject DN output format. + * + * @param cert the certificate being processed + * @return the subject name + */ + protected String getSubjectName(java.security.cert.X509Certificate cert) { + if (cert == null) { + return null; + } + if (! DatatypeHelper.isEmpty(options.x500SubjectDNFormat)) { + return options.x500DNHandler.getName(cert.getSubjectX500Principal(), options.x500SubjectDNFormat); + } else { + return options.x500DNHandler.getName(cert.getSubjectX500Principal()); + } + } + + /** + * Get issuer name from a certificate, using the currently configured X500DNHandler + * and issuer DN output format. + * + * @param cert the certificate being processed + * @return the issuer name + */ + protected String getIssuerName(java.security.cert.X509Certificate cert) { + if (cert == null) { + return null; + } + if (! DatatypeHelper.isEmpty(options.x500IssuerDNFormat)) { + return options.x500DNHandler.getName(cert.getIssuerX500Principal(), options.x500IssuerDNFormat); + } else { + return options.x500DNHandler.getName(cert.getIssuerX500Principal()); + } + } + + /** + * Process the options related to generation of KeyName elements based on the certificate's + * subject DN value. + * + * @param keyInfo the KeyInfo element being processed. + * @param cert the certificate being processed + */ + protected void processSubjectDNKeyName(KeyInfo keyInfo, java.security.cert.X509Certificate cert) { + if (options.emitSubjectDNAsKeyName) { + String subjectNameValue = getSubjectName(cert); + if (! DatatypeHelper.isEmpty(subjectNameValue)) { + KeyInfoHelper.addKeyName(keyInfo, subjectNameValue); + } + } + } + + /** + * Process the options related to generation of KeyName elements based on the + * the common name field(s) of the certificate's subject DN. + * + * @param keyInfo the KeyInfo element being processed. + * @param cert the certificate being processed + */ + protected void processSubjectCNKeyName(KeyInfo keyInfo, java.security.cert.X509Certificate cert) { + if (options.emitSubjectCNAsKeyName) { + for (String name : X509Util.getCommonNames(cert.getSubjectX500Principal())) { + if (! DatatypeHelper.isEmpty(name)) { + KeyInfoHelper.addKeyName(keyInfo, name); + } + } + } + } + + /** + * Process the options related to generation of KeyName elements based on subject + * alternative name information within the certificate data. + * + * @param keyInfo the KeyInfo element being processed. + * @param cert the certificate being processed + */ + protected void processSubjectAltNameKeyNames(KeyInfo keyInfo, java.security.cert.X509Certificate cert) { + if (options.emitSubjectAltNamesAsKeyNames && options.subjectAltNames.size() > 0) { + Integer[] nameTypes = new Integer[ options.subjectAltNames.size() ]; + options.subjectAltNames.toArray(nameTypes); + for (Object altNameValue : X509Util.getAltNames(cert, nameTypes)) { + // Each returned value should either be a String or a DER-encoded byte array. + // See X509Certificate#getSubjectAlternativeNames for the type rules. + if (altNameValue instanceof String) { + KeyInfoHelper.addKeyName(keyInfo, (String) altNameValue); + } else if (altNameValue instanceof byte[]){ + log.warn("Certificate contained an alt name value as a DER-encoded byte[] (not supported)"); + } else { + log.warn("Certificate contained an alt name value with an unexpected type: {}", + altNameValue.getClass().getName()); + } + } + } + } + + /** Process the value of {@link X509Credential#getEntityCertificateChain()}. + * + * @param keyInfo the KeyInfo that is being built + * @param x509Data the X509Data that is being built + * @param credential the Credential that is being processed + * @throws SecurityException thrown if the certificate data can not be encoded from the Java certificate object + */ + protected void processEntityCertificateChain(KeyInfo keyInfo, X509Data x509Data, X509Credential credential) + throws SecurityException { + + if (options.emitEntityCertificateChain && credential.getEntityCertificateChain() != null) { + for (java.security.cert.X509Certificate javaCert : credential.getEntityCertificateChain()) { + try { + X509Certificate xmlCert = KeyInfoHelper.buildX509Certificate(javaCert); + x509Data.getX509Certificates().add(xmlCert); + } catch (CertificateEncodingException e) { + throw new SecurityException("Error generating X509Certificate element " + + "from a certificate in credential's certificate chain", e); + } + } + } + } + + /** Process the value of {@link X509Credential#getCRLs()}. + * + * @param keyInfo the KeyInfo that is being built + * @param x509Data the X509Data that is being built + * @param credential the Credential that is being processed + * @throws SecurityException thrown if the CRL data can not be encoded from the Java certificate object + */ + protected void processCRLs(KeyInfo keyInfo, X509Data x509Data, X509Credential credential) + throws SecurityException { + + if (options.emitCRLs && credential.getCRLs() != null) { + for (java.security.cert.X509CRL javaCRL : credential.getCRLs()) { + try { + X509CRL xmlCRL = KeyInfoHelper.buildX509CRL(javaCRL); + x509Data.getX509CRLs().add(xmlCRL); + } catch (CRLException e) { + throw new SecurityException("Error generating X509CRL element " + + "from a CRL in credential's CRL list", e); + } + } + } + } + + } + + /** + * Options to be used in the production of a {@link KeyInfo} from an {@link X509Credential}. + */ + protected class X509Options extends BasicOptions { + + /** Emit the entity certificate as an X509Certificate element within X509Data. */ + private boolean emitEntityCertificate; + + /** Emit the entity certificate chain as sequence of X509Certificate elements within X509Data. */ + private boolean emitEntityCertificateChain; + + /** Emit the CRL list as sequence of X509CRL elements within X509Data. */ + private boolean emitCRLs; + + /** Emit the entity certificate subject DN as an X509SubjectName element within X509Data. */ + private boolean emitX509SubjectName; + + /** Emit the entity certificate issuer name and serial number as an X509IssuerSerial element within X509Data. */ + private boolean emitX509IssuerSerial; + + /** Emit the entity certificate subject key identifier as an X509SKI element within X509Data. */ + private boolean emitX509SKI; + + /** Emit the entity certificate subject DN as a KeyName element. */ + private boolean emitSubjectDNAsKeyName; + + /** Emit the entity certificate subject DN common name (CN) fields as KeyName elements. */ + private boolean emitSubjectCNAsKeyName; + + /** Emit the entity certificate subject alternative name extension values as KeyName elements. */ + private boolean emitSubjectAltNamesAsKeyNames; + + /** The set of types of subject alternative names to process. */ + private Set subjectAltNames; + + /** Responsible for parsing and serializing X.500 names to/from {@link X500Principal} instances. */ + private X500DNHandler x500DNHandler; + + /** The format specifier for outputting X.500 subject names. */ + private String x500SubjectDNFormat; + + /** The format specifier for outputting X.500 issuer names. */ + private String x500IssuerDNFormat; + + /** Constructor. */ + protected X509Options() { + subjectAltNames = new LazySet(); + x500DNHandler = new InternalX500DNHandler(); + x500SubjectDNFormat = X500DNHandler.FORMAT_RFC2253; + x500IssuerDNFormat = X500DNHandler.FORMAT_RFC2253; + } + + /** {@inheritDoc} */ + protected X509Options clone() { + X509Options clonedOptions = (X509Options) super.clone(); + + clonedOptions.subjectAltNames = new LazySet(); + clonedOptions.subjectAltNames.addAll(this.subjectAltNames); + + clonedOptions.x500DNHandler = this.x500DNHandler.clone(); + + return clonedOptions; + } + + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/security/x509/X509KeyManagerX509CredentialAdapter.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/security/x509/X509KeyManagerX509CredentialAdapter.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/security/x509/X509KeyManagerX509CredentialAdapter.java 17 Aug 2012 15:16:59 -0000 1.1 @@ -0,0 +1,94 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.security.x509; + +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.cert.X509CRL; +import java.security.cert.X509Certificate; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; + +import javax.net.ssl.X509KeyManager; + +import org.opensaml.xml.security.credential.BasicCredential; +import org.opensaml.xml.util.DatatypeHelper; + +/** A class that wraps a {@link X509KeyManager} and exposes it as an {@link X509Credential}. */ +public class X509KeyManagerX509CredentialAdapter extends BasicCredential implements X509Credential { + + /** Alias used to reference the credential in the key manager. */ + private String credentialAlias; + + /** Wrapped key manager. */ + private X509KeyManager keyManager; + + /** + * Constructor. + * + * @param manager wrapped key manager + * @param alias alias used to reference the credential in the key manager + */ + public X509KeyManagerX509CredentialAdapter(X509KeyManager manager, String alias) { + if (manager == null) { + throw new IllegalArgumentException("Key manager may not be null"); + } + keyManager = manager; + + credentialAlias = DatatypeHelper.safeTrimOrNullString(alias); + if (credentialAlias == null) { + throw new IllegalArgumentException("Entity alias may not be null"); + } + } + + /** {@inheritDoc} */ + public Collection getCRLs() { + return Collections.EMPTY_LIST; + } + + /** {@inheritDoc} */ + public X509Certificate getEntityCertificate() { + X509Certificate[] certs = keyManager.getCertificateChain(credentialAlias); + if (certs != null && certs.length > 0) { + return certs[0]; + } + + return null; + } + + /** {@inheritDoc} */ + public Collection getEntityCertificateChain() { + X509Certificate[] certs = keyManager.getCertificateChain(credentialAlias); + if (certs != null && certs.length > 0) { + return Arrays.asList(certs); + } + + return null; + } + + /** {@inheritDoc} */ + public PrivateKey getPrivateKey() { + return keyManager.getPrivateKey(credentialAlias); + } + + /** {@inheritDoc} */ + public PublicKey getPublicKey() { + return getEntityCertificate().getPublicKey(); + } +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/security/x509/X509SubjectKeyIdentifierCriteria.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/security/x509/X509SubjectKeyIdentifierCriteria.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/security/x509/X509SubjectKeyIdentifierCriteria.java 17 Aug 2012 15:17:00 -0000 1.1 @@ -0,0 +1,64 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.security.x509; + +import org.opensaml.xml.security.Criteria; + +/** + * An implementation of {@link Criteria} which specifies criteria based on + * X.509 certificate subject key identifier. + */ +public final class X509SubjectKeyIdentifierCriteria implements Criteria { + + /** X.509 certificate subject key identifier. */ + private byte[] subjectKeyIdentifier; + + /** + * Constructor. + * + * @param ski certificate subject key identifier + */ + public X509SubjectKeyIdentifierCriteria(byte[] ski) { + setSubjectKeyIdentifier(ski); + } + + /** + * Get the subject key identifier. + * + * @return Returns the subject key identifier + */ + public byte[] getSubjectKeyIdentifier() { + return subjectKeyIdentifier; + } + + /** + * Set the subject key identifier. + * + * @param ski The subject key identifier to set. + */ + public void setSubjectKeyIdentifier(byte[] ski) { + if (ski == null || ski.length == 0) { + throw new IllegalArgumentException("Subject key identifier criteria value must be non-null and non-empty"); + } + subjectKeyIdentifier = ski; + } + + + + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/security/x509/X509SubjectNameCriteria.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/security/x509/X509SubjectNameCriteria.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/security/x509/X509SubjectNameCriteria.java 17 Aug 2012 15:16:59 -0000 1.1 @@ -0,0 +1,63 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.security.x509; + +import javax.security.auth.x500.X500Principal; + +import org.opensaml.xml.security.Criteria; + +/** + * An implementation of {@link Criteria} which specifies criteria based on + * X.509 certificate subject name. + */ +public final class X509SubjectNameCriteria implements Criteria { + + /** X.509 certificate subject name. */ + private X500Principal subjectName; + + /** + * Constructor. + * + * @param subject certificate subject name + */ + public X509SubjectNameCriteria(X500Principal subject) { + setSubjectName(subject); + } + + /** + * Get the subject name. + * + * @return Returns the subject name + */ + public X500Principal getSubjectName() { + return subjectName; + } + + /** + * Set the serial number. + * + * @param subject The subject name + */ + public void setSubjectName(X500Principal subject) { + if (subject == null) { + throw new IllegalArgumentException("Subject principal criteria value must be supplied"); + } + this.subjectName = subject; + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/security/x509/X509Util.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/security/x509/X509Util.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/security/x509/X509Util.java 17 Aug 2012 15:16:59 -0000 1.1 @@ -0,0 +1,452 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.security.x509; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.IOException; +import java.security.GeneralSecurityException; +import java.security.PrivateKey; +import java.security.cert.CRLException; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.CertificateParsingException; +import java.security.cert.X509CRL; +import java.security.cert.X509Certificate; +import java.util.Collection; +import java.util.LinkedList; +import java.util.List; + +import javax.security.auth.x500.X500Principal; + +import org.apache.commons.ssl.TrustMaterial; +import org.bouncycastle.asn1.ASN1InputStream; +import org.bouncycastle.asn1.DERObject; +import org.bouncycastle.asn1.DERObjectIdentifier; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.DERSet; +import org.bouncycastle.asn1.DERString; +import org.bouncycastle.asn1.x509.SubjectKeyIdentifier; +import org.bouncycastle.asn1.x509.X509Extensions; +import org.bouncycastle.x509.extension.SubjectKeyIdentifierStructure; +import org.bouncycastle.x509.extension.X509ExtensionUtil; +import org.opensaml.xml.schema.SchemaBuilder; +import org.opensaml.xml.security.SecurityException; +import org.opensaml.xml.security.SecurityHelper; +import org.opensaml.xml.util.DatatypeHelper; +import org.opensaml.xml.util.IPAddressHelper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Utility class for working with X509 objects. + */ +public class X509Util { + + /** Encoding used to store a key or certificate in a file. */ + public static enum ENCODING_FORMAT { + PEM, DER + }; + + /** Common Name (CN) OID. */ + public static final String CN_OID = "2.5.4.3"; + + /** RFC 2459 Other Subject Alt Name type. */ + public static final Integer OTHER_ALT_NAME = new Integer(0); + + /** RFC 2459 RFC 822 (email address) Subject Alt Name type. */ + public static final Integer RFC822_ALT_NAME = new Integer(1); + + /** RFC 2459 DNS Subject Alt Name type. */ + public static final Integer DNS_ALT_NAME = new Integer(2); + + /** RFC 2459 X.400 Address Subject Alt Name type. */ + public static final Integer X400ADDRESS_ALT_NAME = new Integer(3); + + /** RFC 2459 Directory Name Subject Alt Name type. */ + public static final Integer DIRECTORY_ALT_NAME = new Integer(4); + + /** RFC 2459 EDI Party Name Subject Alt Name type. */ + public static final Integer EDI_PARTY_ALT_NAME = new Integer(5); + + /** RFC 2459 URI Subject Alt Name type. */ + public static final Integer URI_ALT_NAME = new Integer(6); + + /** RFC 2459 IP Address Subject Alt Name type. */ + public static final Integer IP_ADDRESS_ALT_NAME = new Integer(7); + + /** RFC 2459 Registered ID Subject Alt Name type. */ + public static final Integer REGISTERED_ID_ALT_NAME = new Integer(8); + + /** Constructed. */ + protected X509Util() { + + } + + /** + * Determines the certificate, from the collection, associated with the private key. + * + * @param certs certificates to check + * @param privateKey entity's private key + * + * @return the certificate associated with entity's private key or null if not certificate in the collection is + * associated with the given private key + * + * @throws SecurityException thrown if the public or private keys checked are of an unsupported type + * + * @since 1.2 + */ + public static X509Certificate determineEntityCertificate(Collection certs, PrivateKey privateKey) + throws SecurityException { + if (certs == null || privateKey == null) { + return null; + } + + for (X509Certificate certificate : certs) { + if (SecurityHelper.matchKeyPair(certificate.getPublicKey(), privateKey)) { + return certificate; + } + } + + return null; + } + + /** + * Gets the commons names that appear within the given distinguished name. The returned list provides the names in + * the order they appeared in the DN. + * + * @param dn the DN to extract the common names from + * + * @return the common names that appear in the DN in the order they appear or null if the given DN is null + */ + public static List getCommonNames(X500Principal dn) { + Logger log = getLogger(); + if (dn == null) { + return null; + } + + log.debug("Extracting CNs from the following DN: {}", dn.toString()); + List commonNames = new LinkedList(); + try { + ASN1InputStream asn1Stream = new ASN1InputStream(dn.getEncoded()); + DERObject parent = asn1Stream.readObject(); + + String cn = null; + DERObject dnComponent; + DERSequence grandChild; + DERObjectIdentifier componentId; + for (int i = 0; i < ((DERSequence) parent).size(); i++) { + dnComponent = ((DERSequence) parent).getObjectAt(i).getDERObject(); + if (!(dnComponent instanceof DERSet)) { + log.debug("No DN components."); + continue; + } + + // Each DN component is a set + for (int j = 0; j < ((DERSet) dnComponent).size(); j++) { + grandChild = (DERSequence) ((DERSet) dnComponent).getObjectAt(j).getDERObject(); + + if (grandChild.getObjectAt(0) != null + && grandChild.getObjectAt(0).getDERObject() instanceof DERObjectIdentifier) { + componentId = (DERObjectIdentifier) grandChild.getObjectAt(0).getDERObject(); + + if (CN_OID.equals(componentId.getId())) { + // OK, this dn component is actually a cn attribute + if (grandChild.getObjectAt(1) != null + && grandChild.getObjectAt(1).getDERObject() instanceof DERString) { + cn = ((DERString) grandChild.getObjectAt(1).getDERObject()).getString(); + commonNames.add(cn); + } + } + } + } + } + + asn1Stream.close(); + + return commonNames; + + } catch (IOException e) { + log.error("Unable to extract common names from DN: ASN.1 parsing failed: " + e); + return null; + } + } + + /** + * Gets the list of alternative names of a given name type. + * + * @param certificate the certificate to extract the alternative names from + * @param nameTypes the name types + * + * @return the alt names, of the given type, within the cert + */ + public static List getAltNames(X509Certificate certificate, Integer[] nameTypes) { + Logger log = getLogger(); + if (certificate == null) { + return null; + } + + List names = new LinkedList(); + Collection> altNames = null; + try { + altNames = X509ExtensionUtil.getSubjectAlternativeNames(certificate); + } catch (CertificateParsingException e) { + log.error("Encountered an problem trying to extract Subject Alternate " + + "Name from supplied certificate: " + e); + return names; + } + + if (altNames != null) { + // 0th position represents the alt name type + // 1st position contains the alt name data + for (List altName : altNames) { + for (Integer nameType : nameTypes) { + if (altName.get(0).equals(nameType)) { + names.add(convertAltNameType(nameType, altName.get(1))); + break; + } + } + } + } + + return names; + } + + /** + * Gets the common name components of the issuer and all the subject alt names of a given type. + * + * @param certificate certificate to extract names from + * @param altNameTypes type of alt names to extract + * + * @return list of subject names in the certificate + */ + @SuppressWarnings("unchecked") + public static List getSubjectNames(X509Certificate certificate, Integer[] altNameTypes) { + List issuerNames = new LinkedList(); + + List entityCertCNs = X509Util.getCommonNames(certificate.getSubjectX500Principal()); + issuerNames.add(entityCertCNs.get(0)); + issuerNames.addAll(X509Util.getAltNames(certificate, altNameTypes)); + + return issuerNames; + } + + /** + * Get the plain (non-DER encoded) value of the Subject Key Identifier extension of an X.509 certificate, if + * present. + * + * @param certificate an X.509 certificate possibly containing a subject key identifier + * @return the plain (non-DER encoded) value of the Subject Key Identifier extension, or null if the certificate + * does not contain the extension + * @throws IOException + */ + public static byte[] getSubjectKeyIdentifier(X509Certificate certificate) { + Logger log = getLogger(); + byte[] derValue = certificate.getExtensionValue(X509Extensions.SubjectKeyIdentifier.getId()); + if (derValue == null || derValue.length == 0) { + return null; + } + + SubjectKeyIdentifier ski = null; + try { + ski = new SubjectKeyIdentifierStructure(derValue); + } catch (IOException e) { + log.error("Unable to extract subject key identifier from certificate: ASN.1 parsing failed: " + e); + return null; + } + + if (ski != null) { + return ski.getKeyIdentifier(); + } else { + return null; + } + } + + /** + * Decodes X.509 certificates in DER or PEM format. + * + * @param certs encoded certs + * + * @return decoded certs + * + * @throws CertificateException thrown if the certificates can not be decoded + * + * @since 1.2 + */ + public static Collection decodeCertificate(File certs) throws CertificateException{ + if(!certs.exists()){ + throw new CertificateException("Certificate file " + certs.getAbsolutePath() + " does not exist"); + } + + if(!certs.canRead()){ + throw new CertificateException("Certificate file " + certs.getAbsolutePath() + " is not readable"); + } + + try{ + return decodeCertificate(DatatypeHelper.fileToByteArray(certs)); + }catch(IOException e){ + throw new CertificateException("Error reading certificate file " + certs.getAbsolutePath(), e); + } + } + + /** + * Decodes X.509 certificates in DER or PEM format. + * + * @param certs encoded certs + * + * @return decoded certs + * + * @throws CertificateException thrown if the certificates can not be decoded + */ + @SuppressWarnings("unchecked") + public static Collection decodeCertificate(byte[] certs) throws CertificateException { + try { + TrustMaterial tm = new TrustMaterial(certs); + return tm.getCertificates(); + } catch (Exception e) { + throw new CertificateException("Unable to decode X.509 certificates", e); + } + } + + /** + * Decodes CRLS in DER or PKCS#7 format. If in PKCS#7 format only the CRLs are decode, the rest of the content is + * ignored. + * + * @param crls encoded CRLs + * + * @return decoded CRLs + * + * @throws CRLException thrown if the CRLs can not be decoded + * + * @since 1.2 + */ + public static Collection decodeCRLs(File crls) throws CRLException{ + if(!crls.exists()){ + throw new CRLException("CRL file " + crls.getAbsolutePath() + " does not exist"); + } + + if(!crls.canRead()){ + throw new CRLException("CRL file " + crls.getAbsolutePath() + " is not readable"); + } + + try{ + return decodeCRLs(DatatypeHelper.fileToByteArray(crls)); + }catch(IOException e){ + throw new CRLException("Error reading CRL file " + crls.getAbsolutePath(), e); + } + } + + /** + * Decodes CRLS in DER or PKCS#7 format. If in PKCS#7 format only the CRLs are decode, the rest of the content is + * ignored. + * + * @param crls encoded CRLs + * + * @return decoded CRLs + * + * @throws CRLException thrown if the CRLs can not be decoded + */ + @SuppressWarnings("unchecked") + public static Collection decodeCRLs(byte[] crls) throws CRLException { + try { + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + return (Collection) cf.generateCRLs(new ByteArrayInputStream(crls)); + } catch (GeneralSecurityException e) { + throw new CRLException("Unable to decode X.509 certificates"); + } + } + + /** + * Gets a formatted string representing identifier information from the supplied credential. + * + *

+ * This could for example be used in logging messages. + *

+ * + *

+ * Often it will be the case that a given credential that is being evaluated will NOT have a value for the entity ID + * property. So extract the certificate subject DN, and if present, the credential's entity ID. + *

+ * + * @param credential the credential for which to produce a token. + * @param handler the X.500 DN handler to use. If null, a new instance of {@link InternalX500DNHandler} will be + * used. + * + * @return a formatted string containing identifier information present in the credential + */ + public static String getIdentifiersToken(X509Credential credential, X500DNHandler handler) { + X500DNHandler x500DNHandler; + if (handler != null) { + x500DNHandler = handler; + } else { + x500DNHandler = new InternalX500DNHandler(); + } + X500Principal x500Principal = credential.getEntityCertificate().getSubjectX500Principal(); + StringBuilder builder = new StringBuilder(); + builder.append('['); + builder.append(String.format("subjectName='%s'", x500DNHandler.getName(x500Principal))); + if (!DatatypeHelper.isEmpty(credential.getEntityId())) { + builder.append(String.format(" |credential entityID='%s'", DatatypeHelper.safeTrimOrNullString(credential + .getEntityId()))); + } + builder.append(']'); + return builder.toString(); + } + + /** + * Convert types returned by Bouncy Castle X509ExtensionUtil.getSubjectAlternativeNames(X509Certificate) to be + * consistent with what is documented for: java.security.cert.X509Certificate#getSubjectAlternativeNames. + * + * @param nameType the alt name type + * @param nameValue the alt name value + * @return converted representation of name value, based on type + */ + private static Object convertAltNameType(Integer nameType, Object nameValue) { + Logger log = getLogger(); + if (DIRECTORY_ALT_NAME.equals(nameType) || DNS_ALT_NAME.equals(nameType) || RFC822_ALT_NAME.equals(nameType) + || URI_ALT_NAME.equals(nameType) || REGISTERED_ID_ALT_NAME.equals(nameType)) { + + // these are just strings in the appropriate format already, return as-is + return nameValue; + } + + if (IP_ADDRESS_ALT_NAME.equals(nameType)) { + // this is a byte[], IP addr in network byte order + return IPAddressHelper.addressToString((byte[]) nameValue); + } + + if (EDI_PARTY_ALT_NAME.equals(nameType) || X400ADDRESS_ALT_NAME.equals(nameType) + || OTHER_ALT_NAME.equals(nameType)) { + + // these have no defined representation, just return a DER-encoded byte[] + return ((DERObject) nameValue).getDEREncoded(); + } + + log.warn("Encountered unknown alt name type '{}', adding as-is", nameType); + return nameValue; + } + + /** + * Get an SLF4J Logger. + * + * @return a Logger instance + */ + private static Logger getLogger() { + return LoggerFactory.getLogger(X509Util.class); + } +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/security/x509/package.html =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/security/x509/package.html,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/security/x509/package.html 17 Aug 2012 15:16:59 -0000 1.1 @@ -0,0 +1,5 @@ + + +X509 based credential and trust class. + + \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/AbstractSignableXMLObject.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/AbstractSignableXMLObject.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/AbstractSignableXMLObject.java 17 Aug 2012 15:17:16 -0000 1.1 @@ -0,0 +1,79 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature; + +import org.opensaml.xml.AbstractXMLObject; +import org.opensaml.xml.util.XMLConstants; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +/** + * Base for signable XMLObjects. + */ +public abstract class AbstractSignableXMLObject extends AbstractXMLObject implements SignableXMLObject { + + /** XMLSecSignatureImpl */ + private Signature signature; + + /** + * Constructor + * + * @param namespaceURI the namespace the element is in + * @param elementLocalName the local name of the XML element this Object represents + * @param namespacePrefix the prefix for the given namespace + */ + protected AbstractSignableXMLObject(String namespaceURI, String elementLocalName, String namespacePrefix) { + super(namespaceURI, elementLocalName, namespacePrefix); + } + + /** {@inheritDoc} */ + public boolean isSigned() { + Element domElement = getDOM(); + + if (domElement == null) { + return false; + } + + NodeList children = domElement.getChildNodes(); + Element childElement; + for (int i = 0; i < children.getLength(); i++) { + if (children.item(i).getNodeType() != Node.ELEMENT_NODE) { + continue; + } + + childElement = (Element) children.item(i); + if (childElement.getNamespaceURI().equals(XMLConstants.XMLSIG_NS) + && childElement.getLocalName().equals(Signature.DEFAULT_ELEMENT_LOCAL_NAME)) { + return true; + } + } + + return false; + } + + /** {@inheritDoc} */ + public Signature getSignature() { + return signature; + } + + /** {@inheritDoc} */ + public void setSignature(Signature newSignature) { + signature = prepareForAssignment(signature, newSignature); + } +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/ContentReference.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/ContentReference.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/ContentReference.java 17 Aug 2012 15:17:15 -0000 1.1 @@ -0,0 +1,36 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature; + +import org.apache.xml.security.signature.XMLSignature; + +/** + * Interface for representing the references to the content that is digitally signed. + * + * Individual implementations of this may with to expose properties, such as the ability to + * set the digest algorithm if it may vary based on runtime information. + */ +public interface ContentReference { + + /** + * Called by the signature marshaller to allow references to be added to the signature. + * + * @param signature the signature object + */ + public void createReference(XMLSignature signature); +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/CryptoBinary.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/CryptoBinary.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/CryptoBinary.java 17 Aug 2012 15:17:14 -0000 1.1 @@ -0,0 +1,53 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature; + +import java.math.BigInteger; + +import javax.xml.namespace.QName; + +import org.opensaml.xml.schema.XSBase64Binary; +import org.opensaml.xml.util.XMLConstants; + +/** + * XMLObject representing XML Digital Signature, version 20020212, CryptoBinary simple type. + */ +public interface CryptoBinary extends XSBase64Binary { + + /** Local name of the XSI type. */ + public static final String TYPE_LOCAL_NAME = "CryptoBinary"; + + /** QName of the XSI type. */ + public static final QName TYPE_NAME = + new QName(XMLConstants.XMLSIG_NS, TYPE_LOCAL_NAME, XMLConstants.XMLSIG_PREFIX); + + /** + * Convenience method to get the value of the element as a BigInteger type. + * + * @return the BigInteger representation of the element's content + */ + public BigInteger getValueBigInt(); + + /** + * Convenience method to set the value of the element as a BigInteger type. + * + * @param bigInt the new BigInteger representation of the element's content + */ + public void setValueBigInt(BigInteger bigInt); + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/DSAKeyValue.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/DSAKeyValue.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/DSAKeyValue.java 17 Aug 2012 15:17:14 -0000 1.1 @@ -0,0 +1,139 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature; + +import javax.xml.namespace.QName; + +import org.opensaml.xml.util.XMLConstants; +import org.opensaml.xml.validation.ValidatingXMLObject; + +/** XMLObject representing XML Digital Signature, version 20020212, DSAKeyValue element. */ +public interface DSAKeyValue extends ValidatingXMLObject { + + /** Element local name. */ + public static final String DEFAULT_ELEMENT_LOCAL_NAME = "DSAKeyValue"; + + /** Default element name. */ + public static final QName DEFAULT_ELEMENT_NAME = new QName(XMLConstants.XMLSIG_NS, DEFAULT_ELEMENT_LOCAL_NAME, + XMLConstants.XMLSIG_PREFIX); + + /** Local name of the XSI type. */ + public static final String TYPE_LOCAL_NAME = "DSAKeyValueType"; + + /** QName of the XSI type. */ + public static final QName TYPE_NAME = new QName(XMLConstants.XMLSIG_NS, TYPE_LOCAL_NAME, XMLConstants.XMLSIG_PREFIX); + + /** + * Get the P child element. + * + * @return the P child element + */ + public P getP(); + + /** + * Set the P child element. + * + * @param newP the new P child element + */ + public void setP(P newP); + + /** + * Get the Q child element. + * + * @return the Q child element + */ + public Q getQ(); + + /** + * Set the Q child element. + * + * @param newQ the new Q child element + */ + public void setQ(Q newQ); + + /** + * Get the G child element. + * + * @return the G child element + */ + public G getG(); + + /** + * Set the G child element. + * + * @param newG the new G child element + */ + public void setG(G newG); + + /** + * Get the Y child element. + * + * @return the Y child element + */ + public Y getY(); + + /** + * Set the Y child element. + * + * @param newY the new Y child element + */ + public void setY(Y newY); + + /** + * Get the J child element. + * + * @return the J child element + */ + public J getJ(); + + /** + * Set the J child element. + * + * @param newJ the new J child element + */ + public void setJ(J newJ); + + /** + * Get the Seed element. + * + * @return the Seed element + */ + public Seed getSeed(); + + /** + * Set the Seed element. + * + * @param newSeed new Seed element + */ + public void setSeed(Seed newSeed); + + /** + * Get the PgenCounter element. + * + * @return the PgenCounter element + */ + public PgenCounter getPgenCounter(); + + /** + * Set the PgenCounter element. + * + * @param newPgenCounter new PgenCounter element + */ + public void setPgenCounter(PgenCounter newPgenCounter); + +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/DigestMethod.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/DigestMethod.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/DigestMethod.java 17 Aug 2012 15:17:15 -0000 1.1 @@ -0,0 +1,62 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature; + + +import javax.xml.namespace.QName; + +import org.opensaml.xml.ElementExtensibleXMLObject; +import org.opensaml.xml.util.XMLConstants; +import org.opensaml.xml.validation.ValidatingXMLObject; + +/** + * XMLObject representing XML Digital Signature, version 20020212, DigestMethod element. + */ +public interface DigestMethod extends ValidatingXMLObject, ElementExtensibleXMLObject { + + /** Element local name. */ + public static final String DEFAULT_ELEMENT_LOCAL_NAME = "DigestMethod"; + + /** Default element name. */ + public static final QName DEFAULT_ELEMENT_NAME = new QName(XMLConstants.XMLSIG_NS, DEFAULT_ELEMENT_LOCAL_NAME, XMLConstants.XMLSIG_PREFIX); + + /** Local name of the XSI type. */ + public static final String TYPE_LOCAL_NAME = "DigestMethodType"; + + /** QName of the XSI type. */ + public static final QName TYPE_NAME = new QName(XMLConstants.XMLSIG_NS, TYPE_LOCAL_NAME, XMLConstants.XMLSIG_PREFIX); + + /** Algorithm attribute name. */ + public static final String ALGORITHM_ATTRIB_NAME = "Algorithm"; + + /** + * Get the Algorithm URI attribute value. + * + * @return the Algorithm URI attribute value + */ + public String getAlgorithm(); + + /** + * + * Set the Algorithm URI attribute value. + * + * @param newAlgorithm the new Algorithm URI attribute value + */ + public void setAlgorithm(String newAlgorithm); + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/DocumentInternalIDContentReference.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/DocumentInternalIDContentReference.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/DocumentInternalIDContentReference.java 17 Aug 2012 15:17:15 -0000 1.1 @@ -0,0 +1,35 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature; + + +/** + * A content reference that references Elements withing the same document by ID attribute. That is the reference is + * #ID where ID is the value of the ID attribute of the Element. + */ +public class DocumentInternalIDContentReference extends URIContentReference { + + /** + * Constructor. The anchor designator (#) must not be included in the ID. + * + * @param referenceID the reference ID of the element to be signed + */ + public DocumentInternalIDContentReference(String referenceID) { + super("#" + referenceID); + } +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/Exponent.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/Exponent.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/Exponent.java 17 Aug 2012 15:17:15 -0000 1.1 @@ -0,0 +1,35 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature; + +import javax.xml.namespace.QName; + +import org.opensaml.xml.util.XMLConstants; + +/** + * XMLObject representing XML Digital Signature, version 20020212, Exponent element. + */ +public interface Exponent extends CryptoBinary { + + /** Element local name */ + public final static String DEFAULT_ELEMENT_LOCAL_NAME = "Exponent"; + + /** Default element name */ + public final static QName DEFAULT_ELEMENT_NAME = new QName(XMLConstants.XMLSIG_NS, DEFAULT_ELEMENT_LOCAL_NAME, XMLConstants.XMLSIG_PREFIX); + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/G.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/G.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/G.java 17 Aug 2012 15:17:14 -0000 1.1 @@ -0,0 +1,36 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature; + +import javax.xml.namespace.QName; + +import org.opensaml.xml.util.XMLConstants; + +/** + * XMLObject representing XML Digital Signature, version 20020212, G element. + */ +public interface G extends CryptoBinary { + + /** Element local name */ + public final static String DEFAULT_ELEMENT_LOCAL_NAME = "G"; + + /** Default element name */ + public final static QName DEFAULT_ELEMENT_NAME = new QName(XMLConstants.XMLSIG_NS, DEFAULT_ELEMENT_LOCAL_NAME, XMLConstants.XMLSIG_PREFIX); + + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/J.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/J.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/J.java 17 Aug 2012 15:17:15 -0000 1.1 @@ -0,0 +1,36 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature; + +import javax.xml.namespace.QName; + +import org.opensaml.xml.util.XMLConstants; + +/** + * XMLObject representing XML Digital Signature, version 20020212, J element. + */ +public interface J extends CryptoBinary { + + /** Element local name */ + public final static String DEFAULT_ELEMENT_LOCAL_NAME = "J"; + + /** Default element name */ + public final static QName DEFAULT_ELEMENT_NAME = new QName(XMLConstants.XMLSIG_NS, DEFAULT_ELEMENT_LOCAL_NAME, XMLConstants.XMLSIG_PREFIX); + + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/KeyInfo.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/KeyInfo.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/KeyInfo.java 17 Aug 2012 15:17:15 -0000 1.1 @@ -0,0 +1,34 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature; + +import javax.xml.namespace.QName; + +import org.opensaml.xml.util.XMLConstants; + +/** XMLObject representing XML Digital Signature, version 20020212, KeyInfo element. */ +public interface KeyInfo extends KeyInfoType { + + /** Element local name. */ + public static final String DEFAULT_ELEMENT_LOCAL_NAME = "KeyInfo"; + + /** Default element name. */ + public static final QName DEFAULT_ELEMENT_NAME = new QName(XMLConstants.XMLSIG_NS, DEFAULT_ELEMENT_LOCAL_NAME, + XMLConstants.XMLSIG_PREFIX); + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/KeyInfoType.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/KeyInfoType.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/KeyInfoType.java 17 Aug 2012 15:17:15 -0000 1.1 @@ -0,0 +1,141 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature; + +import java.util.List; + +import javax.xml.namespace.QName; + +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.encryption.AgreementMethod; +import org.opensaml.xml.encryption.EncryptedKey; +import org.opensaml.xml.util.XMLConstants; +import org.opensaml.xml.validation.ValidatingXMLObject; + +/** XMLObject representing XML Digital Signature, version 20020212, KeyInfoType complex type. */ +public interface KeyInfoType extends ValidatingXMLObject { + + /** Local name of the XSI type. */ + public static final String TYPE_LOCAL_NAME = "KeyInfoType"; + + /** QName of the XSI type. */ + public static final QName TYPE_NAME = new QName(XMLConstants.XMLSIG_NS, TYPE_LOCAL_NAME, XMLConstants.XMLSIG_PREFIX); + + /** Id attribute name. */ + public static final String ID_ATTRIB_NAME = "Id"; + + /** + * Get the Id attribute value. + * + * @return the Id attribute value + */ + public String getID(); + + /** + * Set the Id attribute value. + * + * @param newID the new Id attribute value + */ + public void setID(String newID); + + /** + * Get the list of all XMLObject children. + * + * @return the list of XMLObject children + */ + public List getXMLObjects(); + + /** + * Get the list of XMLObject children whose type or element QName matches the specified QName. + * + * @param typeOrName the QName of the desired elements + * + * @return the matching list of XMLObject children + */ + public List getXMLObjects(QName typeOrName); + + /** + * Get the list of KeyName child elements. + * + * @return the list of KeyName child elements + */ + public List getKeyNames(); + + /** + * Get the list of KeyValue child elements. + * + * @return the list of KeyValue child elements + */ + public List getKeyValues(); + + /** + * Get the list of RetrievalMethod child elements. + * + * @return the list of RetrievalMethod child elements + */ + public List getRetrievalMethods(); + + /** + * Get the list of X509Data child elements. + * + * @return the list of X509Data child elements + */ + public List getX509Datas(); + + /** + * Get the list of PGPData child elements. + * + * @return the list of PGPData child elements + */ + public List getPGPDatas(); + + /** + * Get the list of SPKIData child elements. + * + * @return the list of SPKIData child elements + */ + public List getSPKIDatas(); + + /** + * Get the list of MgmtData child elements. + * + * @return the list of MgmtData child elements + */ + public List getMgmtDatas(); + + /** + * Get the list of AgreementMethod child elements. + * + * Note: AgreementMethod is actually defined in the XML Encryption schema, and is not explicitly defined in the + * KeyInfoType content model, but for convenience this named getter method is exposed. + * + * @return the list of AgreementMethod child elements + */ + public List getAgreementMethods(); + + /** + * Get the list of EncryptedKey child elements + * + * Note: EncryptedKey is actually defined in the XML Encryption schema, and is not explicitly defined in the + * KeyInfoType content model, but for convenience this named getter method is exposed. + * + * @return the list of EncryptedKey child elements + */ + public List getEncryptedKeys(); + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/KeyName.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/KeyName.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/KeyName.java 17 Aug 2012 15:17:15 -0000 1.1 @@ -0,0 +1,36 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature; + +import javax.xml.namespace.QName; + +import org.opensaml.xml.schema.XSString; +import org.opensaml.xml.util.XMLConstants; + +/** + * XMLObject representing XML Digital Signature, version 20020212, KeyName element. + */ +public interface KeyName extends XSString { + + /** Element local name */ + public final static String DEFAULT_ELEMENT_LOCAL_NAME = "KeyName"; + + /** Default element name */ + public final static QName DEFAULT_ELEMENT_NAME = new QName(XMLConstants.XMLSIG_NS, DEFAULT_ELEMENT_LOCAL_NAME, XMLConstants.XMLSIG_PREFIX); + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/KeyValue.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/KeyValue.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/KeyValue.java 17 Aug 2012 15:17:14 -0000 1.1 @@ -0,0 +1,84 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature; + +import javax.xml.namespace.QName; + +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.util.XMLConstants; +import org.opensaml.xml.validation.ValidatingXMLObject; + +/** + * XMLObject representing XML Digital Signature, version 20020212, KeyValue element. + */ +public interface KeyValue extends ValidatingXMLObject { + + /** Element local name */ + public final static String DEFAULT_ELEMENT_LOCAL_NAME = "KeyValue"; + + /** Default element name */ + public final static QName DEFAULT_ELEMENT_NAME = new QName(XMLConstants.XMLSIG_NS, DEFAULT_ELEMENT_LOCAL_NAME, XMLConstants.XMLSIG_PREFIX); + + /** Local name of the XSI type */ + public final static String TYPE_LOCAL_NAME = "KeyValueType"; + + /** QName of the XSI type */ + public final static QName TYPE_NAME = new QName(XMLConstants.XMLSIG_NS, TYPE_LOCAL_NAME, XMLConstants.XMLSIG_PREFIX); + + /** + * Get the DSAKeyValue child element + * + * @return DSAKeyValue child element + */ + public DSAKeyValue getDSAKeyValue(); + + /** + * Set the DSAKeyValue child element + * + * @param newDSAKeyValue the new DSAKeyValue child element + */ + public void setDSAKeyValue(DSAKeyValue newDSAKeyValue); + + /** + * Get the RSAKeyValue child element + * + * @return the RSAKeyValue child element + */ + public RSAKeyValue getRSAKeyValue(); + + /** + * Set the RSAKeyValue child element + * + * @param newRSAKeyValue the new RSAKeyValue child element + */ + public void setRSAKeyValue(RSAKeyValue newRSAKeyValue); + + /** + * Get the wildcard <any> XMLObject child element + * + * @return the wildcard XMLObject child element + */ + public XMLObject getUnknownXMLObject(); + + /** + * Set the wildcard <any> XMLObject child element + * + * @param newXMLObject the wildcard XMLObject child element + */ + public void setUnknownXMLObject(XMLObject newXMLObject); +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/MgmtData.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/MgmtData.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/MgmtData.java 17 Aug 2012 15:17:16 -0000 1.1 @@ -0,0 +1,36 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature; + +import javax.xml.namespace.QName; + +import org.opensaml.xml.schema.XSString; +import org.opensaml.xml.util.XMLConstants; + +/** + * XMLObject representing XML Digital Signature, version 20020212, MgmtData element. + */ +public interface MgmtData extends XSString { + + /** Element local name */ + public final static String DEFAULT_ELEMENT_LOCAL_NAME = "MgmtData"; + + /** Default element name */ + public final static QName DEFAULT_ELEMENT_NAME = new QName(XMLConstants.XMLSIG_NS, DEFAULT_ELEMENT_LOCAL_NAME, XMLConstants.XMLSIG_PREFIX); + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/Modulus.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/Modulus.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/Modulus.java 17 Aug 2012 15:17:14 -0000 1.1 @@ -0,0 +1,35 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature; + +import javax.xml.namespace.QName; + +import org.opensaml.xml.util.XMLConstants; + +/** + * XMLObject representing XML Digital Signature, version 20020212, Modulus element. + */ +public interface Modulus extends CryptoBinary { + + /** Element local name */ + public final static String DEFAULT_ELEMENT_LOCAL_NAME = "Modulus"; + + /** Default element name */ + public final static QName DEFAULT_ELEMENT_NAME = new QName(XMLConstants.XMLSIG_NS, DEFAULT_ELEMENT_LOCAL_NAME, XMLConstants.XMLSIG_PREFIX); + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/P.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/P.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/P.java 17 Aug 2012 15:17:15 -0000 1.1 @@ -0,0 +1,35 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature; + +import javax.xml.namespace.QName; + +import org.opensaml.xml.util.XMLConstants; + +/** + * XMLObject representing XML Digital Signature, version 20020212, P element. + */ +public interface P extends CryptoBinary { + + /** Element local name */ + public final static String DEFAULT_ELEMENT_LOCAL_NAME = "P"; + + /** Default element name */ + public final static QName DEFAULT_ELEMENT_NAME = new QName(XMLConstants.XMLSIG_NS, DEFAULT_ELEMENT_LOCAL_NAME, XMLConstants.XMLSIG_PREFIX); + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/PGPData.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/PGPData.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/PGPData.java 17 Aug 2012 15:17:16 -0000 1.1 @@ -0,0 +1,71 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature; + +import javax.xml.namespace.QName; + +import org.opensaml.xml.ElementExtensibleXMLObject; +import org.opensaml.xml.util.XMLConstants; +import org.opensaml.xml.validation.ValidatingXMLObject; + +/** + * XMLObject representing XML Digital Signature, version 20020212, PGPData element. + */ +public interface PGPData extends ValidatingXMLObject, ElementExtensibleXMLObject { + + /** Element local name */ + public final static String DEFAULT_ELEMENT_LOCAL_NAME = "PGPData"; + + /** Default element name */ + public final static QName DEFAULT_ELEMENT_NAME = new QName(XMLConstants.XMLSIG_NS, DEFAULT_ELEMENT_LOCAL_NAME, XMLConstants.XMLSIG_PREFIX); + + /** Local name of the XSI type */ + public final static String TYPE_LOCAL_NAME = "PGPDataType"; + + /** QName of the XSI type */ + public final static QName TYPE_NAME = new QName(XMLConstants.XMLSIG_NS, TYPE_LOCAL_NAME, XMLConstants.XMLSIG_PREFIX); + + /** + * Get PGPKeyID child element + * + * @return the PGPKeyID child element + */ + public PGPKeyID getPGPKeyID(); + + /** + * Set PGPKeyID child element + * + * @param newPGPKeyID the new PGPKeyID + */ + public void setPGPKeyID(PGPKeyID newPGPKeyID); + + /** + * Get PGPKeyPacket child element + * + * @return the PGPKeyPacket child element + */ + public PGPKeyPacket getPGPKeyPacket(); + + /** + * Set PGPKeyPacket child element + * + * @param newPGPKeyPacket the new PGPKeyPacket + */ + public void setPGPKeyPacket(PGPKeyPacket newPGPKeyPacket); + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/PGPKeyID.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/PGPKeyID.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/PGPKeyID.java 17 Aug 2012 15:17:14 -0000 1.1 @@ -0,0 +1,36 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature; + +import javax.xml.namespace.QName; + +import org.opensaml.xml.schema.XSBase64Binary; +import org.opensaml.xml.util.XMLConstants; + +/** + * XMLObject representing XML Digital Signature, version 20020212, PGPKeyID element. + */ +public interface PGPKeyID extends XSBase64Binary { + + /** Element local name */ + public final static String DEFAULT_ELEMENT_LOCAL_NAME = "PGPKeyID"; + + /** Default element name */ + public final static QName DEFAULT_ELEMENT_NAME = new QName(XMLConstants.XMLSIG_NS, DEFAULT_ELEMENT_LOCAL_NAME, XMLConstants.XMLSIG_PREFIX); + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/PGPKeyPacket.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/PGPKeyPacket.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/PGPKeyPacket.java 17 Aug 2012 15:17:14 -0000 1.1 @@ -0,0 +1,36 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature; + +import javax.xml.namespace.QName; + +import org.opensaml.xml.schema.XSBase64Binary; +import org.opensaml.xml.util.XMLConstants; + +/** + * XMLObject representing XML Digital Signature, version 20020212, PGPKeyPacket element. + */ +public interface PGPKeyPacket extends XSBase64Binary { + + /** Element local name */ + public final static String DEFAULT_ELEMENT_LOCAL_NAME = "PGPKeyPacket"; + + /** Default element name */ + public final static QName DEFAULT_ELEMENT_NAME = new QName(XMLConstants.XMLSIG_NS, DEFAULT_ELEMENT_LOCAL_NAME, XMLConstants.XMLSIG_PREFIX); + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/PgenCounter.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/PgenCounter.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/PgenCounter.java 17 Aug 2012 15:17:14 -0000 1.1 @@ -0,0 +1,35 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature; + +import javax.xml.namespace.QName; + +import org.opensaml.xml.util.XMLConstants; + +/** + * XMLObject representing XML Digital Signature, version 20020212, PgenCounter element. + */ +public interface PgenCounter extends CryptoBinary { + + /** Element local name */ + public final static String DEFAULT_ELEMENT_LOCAL_NAME = "PgenCounter"; + + /** Default element name */ + public final static QName DEFAULT_ELEMENT_NAME = new QName(XMLConstants.XMLSIG_NS, DEFAULT_ELEMENT_LOCAL_NAME, XMLConstants.XMLSIG_PREFIX); + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/Q.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/Q.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/Q.java 17 Aug 2012 15:17:16 -0000 1.1 @@ -0,0 +1,35 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature; + +import javax.xml.namespace.QName; + +import org.opensaml.xml.util.XMLConstants; + +/** + * XMLObject representing XML Digital Signature, version 20020212, Q element. + */ +public interface Q extends CryptoBinary { + + /** Element local name */ + public final static String DEFAULT_ELEMENT_LOCAL_NAME = "Q"; + + /** Default element name */ + public final static QName DEFAULT_ELEMENT_NAME = new QName(XMLConstants.XMLSIG_NS, DEFAULT_ELEMENT_LOCAL_NAME, XMLConstants.XMLSIG_PREFIX); + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/RSAKeyValue.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/RSAKeyValue.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/RSAKeyValue.java 17 Aug 2012 15:17:15 -0000 1.1 @@ -0,0 +1,69 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature; + +import javax.xml.namespace.QName; + +import org.opensaml.xml.util.XMLConstants; +import org.opensaml.xml.validation.ValidatingXMLObject; + +/** XMLObject representing XML Digital Signature, version 20020212, RSAKeyValue element. */ +public interface RSAKeyValue extends ValidatingXMLObject { + + /** Element local name. */ + public static final String DEFAULT_ELEMENT_LOCAL_NAME = "RSAKeyValue"; + + /** Default element name. */ + public static final QName DEFAULT_ELEMENT_NAME = new QName(XMLConstants.XMLSIG_NS, DEFAULT_ELEMENT_LOCAL_NAME, + XMLConstants.XMLSIG_PREFIX); + + /** Local name of the XSI type. */ + public static final String TYPE_LOCAL_NAME = "RSAKeyValueType"; + + /** QName of the XSI type. */ + public static final QName TYPE_NAME = new QName(XMLConstants.XMLSIG_NS, TYPE_LOCAL_NAME, XMLConstants.XMLSIG_PREFIX); + + /** + * Get the Modulus child element. + * + * @return the Modulus child element + */ + public Modulus getModulus(); + + /** + * Set the Modulus child element. + * + * @param newModulus the new Modulus child element + */ + public void setModulus(Modulus newModulus); + + /** + * Get the Exponent child element. + * + * @return the Exponent child element + */ + public Exponent getExponent(); + + /** + * Set the Exponent child element. + * + * @param newExponent the new Exponent child element + */ + public void setExponent(Exponent newExponent); + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/RetrievalMethod.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/RetrievalMethod.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/RetrievalMethod.java 17 Aug 2012 15:17:14 -0000 1.1 @@ -0,0 +1,90 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature; + +import javax.xml.namespace.QName; + +import org.opensaml.xml.util.XMLConstants; +import org.opensaml.xml.validation.ValidatingXMLObject; + +/** + * XMLObject representing XML Digital Signature, version 20020212, RetrievalMethod element. + */ +public interface RetrievalMethod extends ValidatingXMLObject { + + /** Element local name */ + public final static String DEFAULT_ELEMENT_LOCAL_NAME = "RetrievalMethod"; + + /** Default element name */ + public final static QName DEFAULT_ELEMENT_NAME = new QName(XMLConstants.XMLSIG_NS, DEFAULT_ELEMENT_LOCAL_NAME, XMLConstants.XMLSIG_PREFIX); + + /** Local name of the XSI type */ + public final static String TYPE_LOCAL_NAME = "RetrievalMethodType"; + + /** QName of the XSI type */ + public final static QName TYPE_NAME = new QName(XMLConstants.XMLSIG_NS, TYPE_LOCAL_NAME, XMLConstants.XMLSIG_PREFIX); + + /** URI attribute name */ + public static final String URI_ATTRIB_NAME = "URI"; + + /** Type attribute name */ + public static final String TYPE_ATTRIB_NAME = "Type"; + + /** + * Get the URI attribute value + * + * @return the URI attribute value + */ + public String getURI(); + + /** + * Set the URI attribute value + * + * @param newURI the new URI attribute value + */ + public void setURI(String newURI); + + /** + * Set the Type attribute value + * + * @return the Type attribute value + */ + public String getType(); + + /** + * Set the Type attribute value + * + * @param newType the new Type attribute value + */ + public void setType(String newType); + + /** + * Get the Transforms child element + * + * @return the Transforms child element + */ + public Transforms getTransforms(); + + /** + * Set the Transforms child element + * + * @param newTransforms the new Transforms child element + */ + public void setTransforms(Transforms newTransforms); + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/SPKIData.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/SPKIData.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/SPKIData.java 17 Aug 2012 15:17:15 -0000 1.1 @@ -0,0 +1,69 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature; + +import java.util.List; + +import javax.xml.namespace.QName; + +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.util.XMLConstants; +import org.opensaml.xml.validation.ValidatingXMLObject; + +/** + * XMLObject representing XML Digital Signature, version 20020212, SPKIData element. + */ +public interface SPKIData extends ValidatingXMLObject { + + /** Element local name */ + public final static String DEFAULT_ELEMENT_LOCAL_NAME = "SPKIData"; + + /** Default element name */ + public final static QName DEFAULT_ELEMENT_NAME = new QName(XMLConstants.XMLSIG_NS, DEFAULT_ELEMENT_LOCAL_NAME, XMLConstants.XMLSIG_PREFIX); + + /** Local name of the XSI type */ + public final static String TYPE_LOCAL_NAME = "SPKIDataType"; + + /** QName of the XSI type */ + public final static QName TYPE_NAME = new QName(XMLConstants.XMLSIG_NS, TYPE_LOCAL_NAME, XMLConstants.XMLSIG_PREFIX); + + /** + * Get the list of all XMLObject children + * + * @return the list of XMLObject children + */ + public List getXMLObjects(); + + /** + * Get the list of XMLObject children whose type or element + * QName matches the specified QName + * + * @param typeOrName the QName of the desired elements + * + * @return the matching list of XMLObject children + */ + public List getXMLObjects(QName typeOrName); + + /** + * Get the list of SPKISexp child elements + * + * @return the list of SPKISexp child elements + */ + public List getSPKISexps(); + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/SPKISexp.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/SPKISexp.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/SPKISexp.java 17 Aug 2012 15:17:14 -0000 1.1 @@ -0,0 +1,36 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature; + +import javax.xml.namespace.QName; + +import org.opensaml.xml.schema.XSBase64Binary; +import org.opensaml.xml.util.XMLConstants; + +/** + * XMLObject representing XML Digital Signature, version 20020212, SPKISexp element. + */ +public interface SPKISexp extends XSBase64Binary { + + /** Element local name */ + public final static String DEFAULT_ELEMENT_LOCAL_NAME = "SPKISexp"; + + /** Default element name */ + public final static QName DEFAULT_ELEMENT_NAME = new QName(XMLConstants.XMLSIG_NS, DEFAULT_ELEMENT_LOCAL_NAME, XMLConstants.XMLSIG_PREFIX); + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/Seed.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/Seed.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/Seed.java 17 Aug 2012 15:17:16 -0000 1.1 @@ -0,0 +1,35 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature; + +import javax.xml.namespace.QName; + +import org.opensaml.xml.util.XMLConstants; + +/** + * XMLObject representing XML Digital Signature, version 20020212, Seed element. + */ +public interface Seed extends CryptoBinary { + + /** Element local name */ + public final static String DEFAULT_ELEMENT_LOCAL_NAME = "Seed"; + + /** Default element name */ + public final static QName DEFAULT_ELEMENT_NAME = new QName(XMLConstants.XMLSIG_NS, DEFAULT_ELEMENT_LOCAL_NAME, XMLConstants.XMLSIG_PREFIX); + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/SignableXMLObject.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/SignableXMLObject.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/SignableXMLObject.java 17 Aug 2012 15:17:14 -0000 1.1 @@ -0,0 +1,47 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature; + +import org.opensaml.xml.XMLObject; + +/** + * An XMLObject whose DOM representation can be digitally signed. + */ +public interface SignableXMLObject extends XMLObject { + + /** + * Checks to see if the element has been signed. + * + * @return true if this element is signed, false if not + */ + public boolean isSigned(); + + /** + * Gets the Signature XMLObject. + * + * @return the Signature XMLObject + */ + public Signature getSignature(); + + /** + * Sets the Signature XMLObject. + * + * @param newSignature the Signature XMLObject + */ + public void setSignature(Signature newSignature); +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/Signature.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/Signature.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/Signature.java 17 Aug 2012 15:17:15 -0000 1.1 @@ -0,0 +1,125 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature; + +import java.util.List; + +import javax.xml.namespace.QName; + +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.security.credential.Credential; +import org.opensaml.xml.util.XMLConstants; + +/** + * XMLObject representing an enveloped or detached XML Digital Signature, version 20020212, Signature element. + */ +public interface Signature extends XMLObject { + + /** Element local name. */ + public static final String DEFAULT_ELEMENT_LOCAL_NAME = "Signature"; + + /** Default element name. */ + public static final QName DEFAULT_ELEMENT_NAME = new QName(XMLConstants.XMLSIG_NS, DEFAULT_ELEMENT_LOCAL_NAME, + XMLConstants.XMLSIG_PREFIX); + + /** Local name of the XSI type. */ + public static final String TYPE_LOCAL_NAME = "SignatureType"; + + /** QName of the XSI type. */ + public static final QName TYPE_NAME = new QName(XMLConstants.XMLSIG_NS, TYPE_LOCAL_NAME, + XMLConstants.XMLSIG_PREFIX); + + /** + * Gets the canonicalization algorithm used to create the signature content. + * + * @return the canonicalization algorithm used to create the signature content + */ + public String getCanonicalizationAlgorithm(); + + /** + * Sets the canonicalization algorithm used to create the signature content. + * + * @param newAlgorithm the canonicalization algorithm used to create the signature content + */ + public void setCanonicalizationAlgorithm(String newAlgorithm); + + /** + * Gets the algorithm used to compute the signature. + * + * @return the algorithm used to compute the signature + */ + public String getSignatureAlgorithm(); + + /** + * Sets the algorithm used to compute the signature. + * + * @param newAlgorithm the algorithm used to compute the signature + */ + public void setSignatureAlgorithm(String newAlgorithm); + + /** + * Gets the HMAC output length value, optionally used when signing + * with an HMAC signature algorithm. + * + * @return the HMACOutputLength value + */ + public Integer getHMACOutputLength(); + + /** + * Sets the HMAC output length value, optionally used when signing + * with an HMAC signature algorithm. + * + * @param length the new HMACOutputLength value + */ + public void setHMACOutputLength(Integer length); + + /** + * Gets the signature signing credential. + * + * @return the signature signing credential + */ + public Credential getSigningCredential(); + + /** + * Sets the signature signing credential. + * + * @param newCredential the signature signing credential + */ + public void setSigningCredential(Credential newCredential); + + /** + * Gets the key info added to this signature. + * + * @return the key info added to this signature + */ + public KeyInfo getKeyInfo(); + + /** + * Sets the key info added to this signature. + * + * @param newKeyInfo the key info added to this signature + */ + public void setKeyInfo(KeyInfo newKeyInfo); + + /** + * Gets the list of signature content references. + * + * @return the list of signature content references + */ + public List getContentReferences(); +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/SignatureConstants.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/SignatureConstants.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/SignatureConstants.java 17 Aug 2012 15:17:16 -0000 1.1 @@ -0,0 +1,214 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature; + +import org.opensaml.xml.util.XMLConstants; + + +/** + * Constants defined in or related to the XML Signature specification, version 20020112. + */ +public class SignatureConstants { + + /** Namespace URI defined by RFC 4051. */ + public static final String MORE_ALGO_NS = "http://www.w3.org/2001/04/xmldsig-more#"; + + + // ********************************************************* + // Algorithm URI's + // ********************************************************* + + /** Signature - Required DSAwithSHA1 (DSS). */ + public static final String ALGO_ID_SIGNATURE_DSA = XMLConstants.XMLSIG_NS + "dsa-sha1"; + + /** Signature - Recommended RSAwithSHA1 (PKCS1). */ + public static final String ALGO_ID_SIGNATURE_RSA = XMLConstants.XMLSIG_NS + "rsa-sha1"; + + /** Signature - Recommended RSAwithSHA1 (PKCS1). */ + public static final String ALGO_ID_SIGNATURE_RSA_SHA1 = ALGO_ID_SIGNATURE_RSA; + + /** MAC - Required HMAC-SHA1. */ + public static final String ALGO_ID_MAC_HMAC_SHA1 = XMLConstants.XMLSIG_NS + "hmac-sha1"; + + /** Digest - Required SHA1. */ + public static final String ALGO_ID_DIGEST_SHA1 = XMLConstants.XMLSIG_NS + "sha1"; + + /** Encoding - Required Base64. */ + public static final String ALGO_ID_ENCODING_BASE64 = XMLConstants.XMLSIG_NS + "base64"; + + // ********************************************************* + // URI's representing types that may be dereferenced, such + // as in RetrievalMethod/@Type + // ********************************************************* + + /** Type - KeyInfo DSAKeyValue. */ + public static final String TYPE_KEYINFO_DSA_KEYVALUE = XMLConstants.XMLSIG_NS + "DSAKeyValue"; + + /** Type - KeyInfo RSAKeyValue. */ + public static final String TYPE_KEYINFO_RSA_KEYVALUE = XMLConstants.XMLSIG_NS + "RSAKeyValue"; + + /** Type - KeyInfo X509Data. */ + public static final String TYPE_KEYINFO_X509DATA = XMLConstants.XMLSIG_NS + "X509Data"; + + /** Type - KeyInfo PGPData. */ + public static final String TYPE_KEYINFO_PGPDATA = XMLConstants.XMLSIG_NS + "PGPData"; + + /** Type - KeyInfo SPKIData. */ + public static final String TYPE_KEYINFO_SPKIDATA = XMLConstants.XMLSIG_NS + "SPKIData"; + + /** Type - KeyInfo MgmtData. */ + public static final String TYPE_KEYINFO_MGMTDATA = XMLConstants.XMLSIG_NS + "MgmtData"; + + /** Type - A binary (ASN.1 DER) X.509 Certificate. */ + public static final String TYPE_KEYINFO_RAW_X509CERT = XMLConstants.XMLSIG_NS + "rawX509Certificate"; + + /** Type - Signature Object. */ + //public static final String TYPE_SIGNATURE_OBJECT = XMLConstants.XMLSIG_NS + "Object"; + + /** Type - Signature Manifest. */ + //public static final String TYPE_SIGNATURE_MANIFEST = XMLConstants.XMLSIG_NS + "Manifest"; + + /** Type - Signature SignatureProperties. */ + //public static final String TYPE_SIGNATURE_SIGNATURE_PROPERTIES = XMLConstants.XMLSIG_NS + "SignatureProperties"; + + // These are additional type URI's defined by RFC 4051 + + /** Type - KeyInfo KeyValue. */ + public static final String TYPE_KEYINFO_KEYVALUE = MORE_ALGO_NS + "KeyValue"; + + /** Type - KeyInfo RetrievalMethod. */ + public static final String TYPE_KEYINFO_RETRIEVAL_METHOD = MORE_ALGO_NS + "RetrievalMethod"; + + /** Type - KeyInfo KeyName. */ + public static final String TYPE_KEYINFO_KEYNAME = MORE_ALGO_NS + "KeyName"; + + /** Type - A binary X.509 CRL. */ + public static final String TYPE_KEYINFO_RAW_X509CRL = MORE_ALGO_NS + "rawX509CRL"; + + /** Type - A binary PGP key packet. */ + public static final String TYPE_KEYINFO_RAW_PGP_KEYPACKET = MORE_ALGO_NS + "rawPGPKeyPacket"; + + /** Type - A raw SPKI S-expression. */ + public static final String TYPE_KEYINFO_RAW_SPKI_SEXP = MORE_ALGO_NS + "rawSPKISexp"; + + /** Type - A PKCS7signedData element. */ + public static final String TYPE_KEYINFO_PKCS7_SIGNED_DATA = MORE_ALGO_NS + "PKCS7signedData"; + + /** Type - Binary PKCS7 signed data. */ + public static final String TYPE_KEYINFO_RAW_PKCS7_SIGNED_DATA = MORE_ALGO_NS + "rawPKCS7signedData"; + + + // ********************************************************* + // Canonicalization + // ********************************************************* + + /** Canonicalization - Inclusive WITHOUT comments. */ + public static final String ALGO_ID_C14N_OMIT_COMMENTS = "http://www.w3.org/TR/2001/REC-xml-c14n-20010315"; + + /** Canonicalization - Inclusive WITH comments. */ + public static final String ALGO_ID_C14N_WITH_COMMENTS = ALGO_ID_C14N_OMIT_COMMENTS + "#WithComments"; + + /** Canonicalization - Exclusive WITHOUT comments. */ + public static final String ALGO_ID_C14N_EXCL_OMIT_COMMENTS = "http://www.w3.org/2001/10/xml-exc-c14n#"; + + /** Canonicalization - Exclusive WITH comments. */ + public static final String ALGO_ID_C14N_EXCL_WITH_COMMENTS = ALGO_ID_C14N_EXCL_OMIT_COMMENTS + "WithComments"; + + + // ********************************************************* + // Transforms + // ********************************************************* + + /** Transform - Required Enveloped Signature. */ + public static final String TRANSFORM_ENVELOPED_SIGNATURE = XMLConstants.XMLSIG_NS + "enveloped-signature"; + + /** Transform - Required Inclusive c14n WITHOUT comments. */ + public static final String TRANSFORM_C14N_OMIT_COMMENTS = ALGO_ID_C14N_OMIT_COMMENTS; + + /** Transform - Recommended Inclusive c14n WITH comments. */ + public static final String TRANSFORM_C14N_WITH_COMMENTS = ALGO_ID_C14N_WITH_COMMENTS; + + /** Transform - Exclusive c14n WITHOUT comments. */ + public static final String TRANSFORM_C14N_EXCL_OMIT_COMMENTS = ALGO_ID_C14N_EXCL_OMIT_COMMENTS; + + /** Transform - Exclusive c14n WITH comments. */ + public static final String TRANSFORM_C14N_EXCL_WITH_COMMENTS = ALGO_ID_C14N_EXCL_WITH_COMMENTS; + + /** Transform - Optional XSLT. */ + public static final String TRANSFORM_XSLT = "http://www.w3.org/TR/1999/REC-xslt-19991116"; + + /** Transform - Recommended XPath. */ + public static final String TRANSFORM_XPATH = "http://www.w3.org/TR/1999/REC-xpath-19991116"; + + /** Transform - Base64 Decode. */ + public static final String TRANSFORM_BASE64_DECODE = XMLConstants.XMLSIG_NS + "base64"; + + /* + public static final String TRANSFORM_XPOINTER = "http://www.w3.org/TR/2001/WD-xptr-20010108"; + public static final String TRANSFORM_XPATH2FILTER04 = "http://www.w3.org/2002/04/xmldsig-filter2"; + public static final String TRANSFORM_XPATH2FILTER = "http://www.w3.org/2002/06/xmldsig-filter2"; + */ + + + // ********************************************************* + // Some additional algorithm URI's from RFC 4051 + // ********************************************************* + /** Signature - NOT Recommended RSAwithMD5. */ + public static final String ALGO_ID_SIGNATURE_NOT_RECOMMENDED_RSA_MD5 = MORE_ALGO_NS + "rsa-md5"; + + /** Signature - Optional RSAwithRIPEMD160. */ + public static final String ALGO_ID_SIGNATURE_RSA_RIPEMD160 = MORE_ALGO_NS + "rsa-ripemd160"; + + /** Signature - Optional RSAwithSHA256. */ + public static final String ALGO_ID_SIGNATURE_RSA_SHA256 = MORE_ALGO_NS + "rsa-sha256"; + + /** Signature - Optional RSAwithSHA384. */ + public static final String ALGO_ID_SIGNATURE_RSA_SHA384 = MORE_ALGO_NS + "rsa-sha384"; + + /** Signature - Optional RSAwithSHA512. */ + public static final String ALGO_ID_SIGNATURE_RSA_SHA512 = MORE_ALGO_NS + "rsa-sha512"; + + /** HMAC - NOT Recommended HMAC-MD5. */ + public static final String ALGO_ID_MAC_HMAC_NOT_RECOMMENDED_MD5 = MORE_ALGO_NS + "hmac-md5"; + + /** HMAC - Optional HMAC-RIPEMD160. */ + public static final String ALGO_ID_MAC_HMAC_RIPEMD160 = MORE_ALGO_NS + "hmac-ripemd160"; + + /** HMAC - Optional HMAC-SHA256. */ + public static final String ALGO_ID_MAC_HMAC_SHA256 = MORE_ALGO_NS + "hmac-sha256"; + + /** HMAC - Optional HMAC-SHA284. */ + public static final String ALGO_ID_MAC_HMAC_SHA384 = MORE_ALGO_NS + "hmac-sha384"; + + /** HMAC - Optional HMAC-SHA512. */ + public static final String ALGO_ID_MAC_HMAC_SHA512 = MORE_ALGO_NS + "hmac-sha512"; + + /** Signature - Optional ECDSAwithSHA1. */ + public static final String ALGO_ID_SIGNATURE_ECDSA_SHA1 = MORE_ALGO_NS + "ecdsa-sha1"; + + /** Digest - Optional MD5. */ + public static final String ALGO_ID_DIGEST_NOT_RECOMMENDED_MD5 = MORE_ALGO_NS + "md5"; + + /** Digest - Optional SHA224. */ + // Apache XML-Security doesn't support this + //public static final String ALGO_ID_DIGEST_SHA224 = MORE_ALGO_NS + "sha224"; + + /** Digest - Optional SHA384. */ + public static final String ALGO_ID_DIGEST_SHA384 = MORE_ALGO_NS + "sha384"; + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/SignatureException.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/SignatureException.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/SignatureException.java 17 Aug 2012 15:17:14 -0000 1.1 @@ -0,0 +1,66 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature; + +/** + * Exception thrown when an error occurs during signature operations. + */ +public class SignatureException extends Exception { + + /** + * Serial version UID. + */ + private static final long serialVersionUID = 7879866991794922684L; + + /** + * Constructor. + */ + public SignatureException() { + super(); + } + + /** + * Constructor. + * + * @param message exception message + */ + public SignatureException(String message) { + super(message); + } + + /** + * Constructor. + * + * @param wrappedException exception to be wrapped by this one + */ + public SignatureException(Exception wrappedException) { + super(wrappedException); + } + + /** + * Constructor. + * + * @param message exception message + * @param wrappedException exception to be wrapped by this one + */ + public SignatureException(String message, Exception wrappedException) { + super(message, wrappedException); + } + + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/SignatureTrustEngine.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/SignatureTrustEngine.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/SignatureTrustEngine.java 17 Aug 2012 15:17:16 -0000 1.1 @@ -0,0 +1,71 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature; + +import org.opensaml.xml.security.CriteriaSet; +import org.opensaml.xml.security.SecurityException; +import org.opensaml.xml.security.credential.Credential; +import org.opensaml.xml.security.keyinfo.KeyInfoCredentialResolver; +import org.opensaml.xml.security.trust.TrustEngine; + +/** + * Evaluates the trustworthiness and validity of XML or raw Signatures against implementation-specific requirements. + */ +public interface SignatureTrustEngine extends TrustEngine { + + /** + * Get the KeyInfoCredentialResolver instance used to resolve (advisory) signing credential information + * from KeyInfo elements contained within a Signature element. + * + * Note that credential(s) obtained via this resolver are not themselves trusted. They must be evaluated + * against the trusted credential information obtained from the trusted credential resolver. + * + * @return a KeyInfoCredentialResolver instance + */ + public KeyInfoCredentialResolver getKeyInfoResolver(); + + /** + * Determines whether a raw signature over specified content is valid and signed by a trusted credential. + * + *

A candidate verification credential may optionally be supplied. If one is supplied and is + * determined to successfully verify the signature, an attempt will be made to establish + * trust on this basis.

+ * + *

If a candidate credential is not supplied, or it does not successfully verify the signature, + * some implementations may be able to resolve candidate verification credential(s) in an + * implementation-specific manner based on the trusted criteria supplied, and then attempt + * to verify the signature and establish trust on this basis.

+ * + * @param signature the signature value + * @param content the content that was signed + * @param algorithmURI the signature algorithm URI which was used to sign the content + * @param trustBasisCriteria criteria used to describe and/or resolve the information + * which serves as the basis for trust evaluation + * @param candidateCredential the untrusted candidate credential containing the validation key + * for the signature (optional) + * + * @return true if the signature was valid for the provided content and was signed by a key + * contained within a credential established as trusted based on the supplied criteria, + * otherwise false + * + * @throws SecurityException thrown if there is a problem attempting to verify the signature such as the signature + * algorithim not being supported + */ + public boolean validate(byte[] signature, byte[] content, String algorithmURI, CriteriaSet trustBasisCriteria, + Credential candidateCredential) throws SecurityException; +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/SignatureValidator.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/SignatureValidator.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/SignatureValidator.java 17 Aug 2012 15:17:14 -0000 1.1 @@ -0,0 +1,95 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature; + +import java.security.Key; + +import org.apache.xml.security.signature.XMLSignature; +import org.apache.xml.security.signature.XMLSignatureException; +import org.opensaml.xml.security.SecurityHelper; +import org.opensaml.xml.security.credential.Credential; +import org.opensaml.xml.signature.impl.SignatureImpl; +import org.opensaml.xml.validation.ValidationException; +import org.opensaml.xml.validation.Validator; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * A validator that validates an XML Signature on its content. + */ +public class SignatureValidator implements Validator { + + /** Class logger. */ + private final Logger log = LoggerFactory.getLogger(SignatureValidator.class); + + /** Credential used to validate signature. */ + private Credential validationCredential; + + /** + * Constructor. + * + * @param validatingCredential credential used to validate the signature + */ + public SignatureValidator(Credential validatingCredential) { + validationCredential = validatingCredential; + } + + /** {@inheritDoc} */ + public void validate(Signature signature) throws ValidationException { + log.debug("Attempting to validate signature using key from supplied credential"); + + XMLSignature xmlSig = buildSignature(signature); + + Key validationKey = SecurityHelper.extractVerificationKey(validationCredential); + if (validationKey == null) { + log.debug("Supplied credential contained no key suitable for signature validation"); + throw new ValidationException("No key available to validate signature"); + } + + log.debug("Validating signature with signature algorithm URI: {}", signature.getSignatureAlgorithm()); + log.debug("Validation credential key algorithm '{}', key instance class '{}'", + validationKey.getAlgorithm(), validationKey.getClass().getName()); + + try { + if (xmlSig.checkSignatureValue(validationKey)) { + log.debug("Signature validated with key from supplied credential"); + return; + } + } catch (XMLSignatureException e) { + throw new ValidationException("Unable to evaluate key against signature", e); + } + + log.debug("Signature did not validate against the credential's key"); + + throw new ValidationException("Signature did not validate against the credential's key"); + } + + /** + * Constructs an {@link XMLSignature} from the given signature object. + * + * @param signature the signature + * + * @return the constructed XMLSignature + */ + protected XMLSignature buildSignature(Signature signature) { + log.debug("Creating XMLSignature object"); + + return ((SignatureImpl) signature).getXMLSignature(); + } + +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/Signer.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/Signer.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/Signer.java 17 Aug 2012 15:17:15 -0000 1.1 @@ -0,0 +1,103 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature; + +import java.util.List; + +import org.apache.xml.security.Init; +import org.apache.xml.security.exceptions.XMLSecurityException; +import org.apache.xml.security.signature.XMLSignature; +import org.opensaml.xml.security.SecurityHelper; +import org.opensaml.xml.signature.impl.SignatureImpl; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * This class is responsible for creating the digital signatures for the given signable XMLObjects. + * + * This must be done as a seperate step because in order to support the following cases: + *
    + *
  • Multiple signable objects appear in the DOM tree, in which case the order that the objects should be signed in + * is not known (e.g. object 1 could appear first in the tree, but contain a reference to signable object 2)
  • + *
  • The DOM tree resulting from marshalling of the XMLObject tree is grafted onto another DOM tree which may cause + * element ID conflicts that would invalidate the signature
  • + *
+ */ +public class Signer { + + /** Constructor. */ + protected Signer() { + + } + + /** + * Signs the given XMLObject in the order provided. + * + * @param xmlObjects an orderded list of XMLObject to be signed + * @throws SignatureException thrown if there is an error computing the signature + */ + public static void signObjects(List xmlObjects) throws SignatureException { + for (Signature xmlObject : xmlObjects) { + signObject(xmlObject); + } + } + + /** + * Signs a single XMLObject. + * + * @param signature the signature to computer the signature on + * @throws SignatureException thrown if there is an error computing the signature + */ + public static void signObject(Signature signature) throws SignatureException { + Logger log = getLogger(); + try { + XMLSignature xmlSignature = ((SignatureImpl) signature).getXMLSignature(); + + if (xmlSignature == null) { + log.error("Unable to compute signature, Signature XMLObject does not have the XMLSignature " + + "created during marshalling."); + throw new SignatureException("XMLObject does not have an XMLSignature instance, unable to compute signature"); + } + log.debug("Computing signature over XMLSignature object"); + xmlSignature.sign(SecurityHelper.extractSigningKey(signature.getSigningCredential())); + } catch (XMLSecurityException e) { + log.error("An error occured computing the digital signature", e); + throw new SignatureException("Signature computation error", e); + } + } + + /** + * Get an SLF4J Logger. + * + * @return a Logger instance + */ + private static Logger getLogger() { + return LoggerFactory.getLogger(Signer.class); + } + + /* + * Initialize the Apache XML security library if it hasn't been already + */ + static { + Logger log = getLogger(); + if (!Init.isInitialized()) { + log.debug("Initializing XML security library"); + Init.init(); + } + } +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/Transform.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/Transform.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/Transform.java 17 Aug 2012 15:17:15 -0000 1.1 @@ -0,0 +1,87 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature; + + +import java.util.List; + +import javax.xml.namespace.QName; + +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.util.XMLConstants; +import org.opensaml.xml.validation.ValidatingXMLObject; + +/** + * XMLObject representing XML Digital Signature, version 20020212, Transform element. + */ +public interface Transform extends ValidatingXMLObject { + + /** Element local name */ + public final static String DEFAULT_ELEMENT_LOCAL_NAME = "Transform"; + + /** Default element name */ + public final static QName DEFAULT_ELEMENT_NAME = new QName(XMLConstants.XMLSIG_NS, DEFAULT_ELEMENT_LOCAL_NAME, XMLConstants.XMLSIG_PREFIX); + + /** Local name of the XSI type */ + public final static String TYPE_LOCAL_NAME = "TransformType"; + + /** QName of the XSI type */ + public final static QName TYPE_NAME = new QName(XMLConstants.XMLSIG_NS, TYPE_LOCAL_NAME, XMLConstants.XMLSIG_PREFIX); + + /** Algorithm attribute name */ + public final static String ALGORITHM_ATTRIB_NAME = "Algorithm"; + + /** + * Get the Algorithm URI attribute value + * + * @return the Algorithm URI attribute value + */ + public String getAlgorithm(); + + /** + * + * Set the Algorithm URI attribute value + * + * @param newAlgorithm the new Algorithm URI attribute value + */ + public void setAlgorithm(String newAlgorithm); + + /** + * Get the list of XMLObject children that match a particular QName + * + * @param typeOrName the QName of the statements to return + * + * @return the list of XMLObject children that match the given QName + */ + public List getXMLObjects(QName typeOrName); + + /** + * Get the list of XPath child elements + * + * @return list of XPath child elements + */ + public List getXPaths(); + + /** + * Gets the ordered list of all XMLObject child elements of this element. + * + * @return list of XMLObject children + */ + public List getAllChildren(); + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/Transforms.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/Transforms.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/Transforms.java 17 Aug 2012 15:17:15 -0000 1.1 @@ -0,0 +1,51 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature; + +import java.util.List; + +import javax.xml.namespace.QName; + +import org.opensaml.xml.util.XMLConstants; +import org.opensaml.xml.validation.ValidatingXMLObject; + +/** + * XMLObject representing XML Digital Signature, version 20020212, Transforms element. + */ +public interface Transforms extends ValidatingXMLObject { + + /** Element local name */ + public final static String DEFAULT_ELEMENT_LOCAL_NAME = "Transforms"; + + /** Default element name */ + public final static QName DEFAULT_ELEMENT_NAME = new QName(XMLConstants.XMLSIG_NS, DEFAULT_ELEMENT_LOCAL_NAME, XMLConstants.XMLSIG_PREFIX); + + /** Local name of the XSI type */ + public final static String TYPE_LOCAL_NAME = "TransformsType"; + + /** QName of the XSI type */ + public final static QName TYPE_NAME = new QName(XMLConstants.XMLSIG_NS, TYPE_LOCAL_NAME, XMLConstants.XMLSIG_PREFIX); + + /** + * Get the list of Transform child elements + * + * @return a List of Transform child elements + */ + public List getTransforms(); + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/URIContentReference.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/URIContentReference.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/URIContentReference.java 17 Aug 2012 15:17:15 -0000 1.1 @@ -0,0 +1,95 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature; + +import java.util.LinkedList; +import java.util.List; + +import org.apache.xml.security.signature.XMLSignature; +import org.apache.xml.security.transforms.Transforms; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * A generic content reference that uses a URI to reference the content to be signed. + */ +public class URIContentReference implements ContentReference { + + /** Logger. */ + private final Logger log = LoggerFactory.getLogger(URIContentReference.class); + + /** Element reference ID. */ + private String referenceID; + + /** Algorithm used to digest the content . */ + private String digestAlgorithm; + + /** Transforms applied to the content. */ + private List transforms; + + /** + * Constructor. The anchor designator (#) must not be included in the ID. + * + * @param referenceID the reference ID of the element to be signed + */ + public URIContentReference(String referenceID) { + this.referenceID = referenceID; + transforms = new LinkedList(); + } + + /** + * Gets the transforms applied to the content prior to digest generation. + * + * @return the transforms applied to the content prior to digest generation + */ + public List getTransforms() { + return transforms; + } + + /** + * Gets the algorithm used to digest the content. + * + * @return the algorithm used to digest the content + */ + public String getDigestAlgorithm() { + return digestAlgorithm; + } + + /** + * Sets the algorithm used to digest the content. + * + * @param newAlgorithm the algorithm used to digest the content + */ + public void setDigestAlgorithm(String newAlgorithm) { + digestAlgorithm = newAlgorithm; + } + + /** {@inheritDoc} */ + public void createReference(XMLSignature signature) { + try { + Transforms dsigTransforms = new Transforms(signature.getDocument()); + for (String transform : transforms) { + dsigTransforms.addTransform(transform); + } + + signature.addDocument(referenceID, dsigTransforms, digestAlgorithm); + } catch (Exception e) { + log.error("Error while adding content reference", e); + } + } +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/X509CRL.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/X509CRL.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/X509CRL.java 17 Aug 2012 15:17:14 -0000 1.1 @@ -0,0 +1,35 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature; + +import javax.xml.namespace.QName; + +import org.opensaml.xml.schema.XSBase64Binary; +import org.opensaml.xml.util.XMLConstants; + +/** XMLObject representing XML Digital Signature, version 20020212, X509CRL element. */ +public interface X509CRL extends XSBase64Binary { + + /** Element local name. */ + public static final String DEFAULT_ELEMENT_LOCAL_NAME = "X509CRL"; + + /** Default element name. */ + public static final QName DEFAULT_ELEMENT_NAME = new QName(XMLConstants.XMLSIG_NS, DEFAULT_ELEMENT_LOCAL_NAME, + XMLConstants.XMLSIG_PREFIX); + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/X509Certificate.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/X509Certificate.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/X509Certificate.java 17 Aug 2012 15:17:16 -0000 1.1 @@ -0,0 +1,35 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature; + +import javax.xml.namespace.QName; + +import org.opensaml.xml.schema.XSBase64Binary; +import org.opensaml.xml.util.XMLConstants; + +/** XMLObject representing XML Digital Signature, version 20020212, X509Certificate element. */ +public interface X509Certificate extends XSBase64Binary { + + /** Element local name. */ + public static final String DEFAULT_ELEMENT_LOCAL_NAME = "X509Certificate"; + + /** Default element name. */ + public static final QName DEFAULT_ELEMENT_NAME = new QName(XMLConstants.XMLSIG_NS, DEFAULT_ELEMENT_LOCAL_NAME, + XMLConstants.XMLSIG_PREFIX); + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/X509Data.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/X509Data.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/X509Data.java 17 Aug 2012 15:17:14 -0000 1.1 @@ -0,0 +1,95 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature; + +import java.util.List; + +import javax.xml.namespace.QName; + +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.util.XMLConstants; +import org.opensaml.xml.validation.ValidatingXMLObject; + +/** XMLObject representing XML Digital Signature, version 20020212, X509Data element. */ +public interface X509Data extends ValidatingXMLObject { + + /** Element local name. */ + public static final String DEFAULT_ELEMENT_LOCAL_NAME = "X509Data"; + + /** Default element name. */ + public static final QName DEFAULT_ELEMENT_NAME = new QName(XMLConstants.XMLSIG_NS, DEFAULT_ELEMENT_LOCAL_NAME, + XMLConstants.XMLSIG_PREFIX); + + /** Local name of the XSI type. */ + public static final String TYPE_LOCAL_NAME = "X509DataType"; + + /** QName of the XSI type. */ + public static final QName TYPE_NAME = new QName(XMLConstants.XMLSIG_NS, TYPE_LOCAL_NAME, XMLConstants.XMLSIG_PREFIX); + + /** + * Get the list of all XMLObject children. + * + * @return the list of XMLObject children + */ + public List getXMLObjects(); + + /** + * Get the list of XMLObject children whose type or element QName matches the specified QName. + * + * @param typeOrName the QName of the desired elements + * + * @return the matching list of XMLObject children + */ + public List getXMLObjects(QName typeOrName); + + /** + * Get the list of X509IssuerSerial child elements. + * + * @return the list of X509IssuerSerial child elements + */ + public List getX509IssuerSerials(); + + /** + * Get the list of X509SKI child elements. + * + * @return the list of X509SKI child elements + */ + public List getX509SKIs(); + + /** + * Get the list of X509SubjectName child elements. + * + * @return the list of X509SubjectName child elements + */ + public List getX509SubjectNames(); + + /** + * Get the list of X509Certificate child elements. + * + * @return the list of X509Certificate child elements + */ + public List getX509Certificates(); + + /** + * Get the list of X509CRL child elements. + * + * @return the list of X509CRL child elements + */ + public List getX509CRLs(); + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/X509IssuerName.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/X509IssuerName.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/X509IssuerName.java 17 Aug 2012 15:17:14 -0000 1.1 @@ -0,0 +1,35 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature; + +import javax.xml.namespace.QName; + +import org.opensaml.xml.schema.XSString; +import org.opensaml.xml.util.XMLConstants; + +/** XMLObject representing XML Digital Signature, version 20020212, X509IssuerName element. */ +public interface X509IssuerName extends XSString { + + /** Element local name. */ + public static final String DEFAULT_ELEMENT_LOCAL_NAME = "X509IssuerName"; + + /** Default element name. */ + public static final QName DEFAULT_ELEMENT_NAME = new QName(XMLConstants.XMLSIG_NS, DEFAULT_ELEMENT_LOCAL_NAME, + XMLConstants.XMLSIG_PREFIX); + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/X509IssuerSerial.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/X509IssuerSerial.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/X509IssuerSerial.java 17 Aug 2012 15:17:15 -0000 1.1 @@ -0,0 +1,69 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature; + +import javax.xml.namespace.QName; + +import org.opensaml.xml.util.XMLConstants; +import org.opensaml.xml.validation.ValidatingXMLObject; + +/** XMLObject representing XML Digital Signature, version 20020212, X509IssuerSerial element. */ +public interface X509IssuerSerial extends ValidatingXMLObject { + + /** Element local name. */ + public static final String DEFAULT_ELEMENT_LOCAL_NAME = "X509IssuerSerial"; + + /** Default element name. */ + public static final QName DEFAULT_ELEMENT_NAME = new QName(XMLConstants.XMLSIG_NS, DEFAULT_ELEMENT_LOCAL_NAME, + XMLConstants.XMLSIG_PREFIX); + + /** Local name of the XSI type. */ + public static final String TYPE_LOCAL_NAME = "X509IssuerSerialType"; + + /** QName of the XSI type. */ + public static final QName TYPE_NAME = new QName(XMLConstants.XMLSIG_NS, TYPE_LOCAL_NAME, XMLConstants.XMLSIG_PREFIX); + + /** + * Get the X509IssuerName child element. + * + * @return the X509Issuername child element + */ + public X509IssuerName getX509IssuerName(); + + /** + * Set the X509IssuerName child element. + * + * @param newX509IssuerName the new X509IssuerName child element + */ + public void setX509IssuerName(X509IssuerName newX509IssuerName); + + /** + * Get the X509SerialNumber child element. + * + * @return the X509SerialNumber child element + */ + public X509SerialNumber getX509SerialNumber(); + + /** + * Set the X509SerialNumber child element. + * + * @param newX509SerialNumber the new X509SerialNumber child element + */ + public void setX509SerialNumber(X509SerialNumber newX509SerialNumber); + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/X509SKI.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/X509SKI.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/X509SKI.java 17 Aug 2012 15:17:14 -0000 1.1 @@ -0,0 +1,35 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature; + +import javax.xml.namespace.QName; + +import org.opensaml.xml.schema.XSBase64Binary; +import org.opensaml.xml.util.XMLConstants; + +/** MLObject representing XML Digital Signature, version 20020212, X509SKI element. */ +public interface X509SKI extends XSBase64Binary { + + /** Element local name. */ + public static final String DEFAULT_ELEMENT_LOCAL_NAME = "X509SKI"; + + /** Default element name. */ + public static final QName DEFAULT_ELEMENT_NAME = new QName(XMLConstants.XMLSIG_NS, DEFAULT_ELEMENT_LOCAL_NAME, + XMLConstants.XMLSIG_PREFIX); + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/X509SerialNumber.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/X509SerialNumber.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/X509SerialNumber.java 17 Aug 2012 15:17:14 -0000 1.1 @@ -0,0 +1,59 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature; + +import java.math.BigInteger; + +import javax.xml.namespace.QName; + +import org.opensaml.xml.util.XMLConstants; +import org.opensaml.xml.validation.ValidatingXMLObject; + +/** + * XMLObject representing XML Digital Signature, version 20020212, X509SerialNumber element. + */ +public interface X509SerialNumber extends ValidatingXMLObject { + + /** Element local name. */ + public static final String DEFAULT_ELEMENT_LOCAL_NAME = "X509SerialNumber"; + + /** Default element name. */ + public static final QName DEFAULT_ELEMENT_NAME = + new QName(XMLConstants.XMLSIG_NS, DEFAULT_ELEMENT_LOCAL_NAME, XMLConstants.XMLSIG_PREFIX); + + /** Local name of the XSI type. */ + public static final String TYPE_LOCAL_NAME = "integer"; + + /** QName of the XSI type. */ + public static final QName TYPE_NAME = new QName(XMLConstants.XSD_NS, TYPE_LOCAL_NAME, XMLConstants.XSD_PREFIX); + + /** + * Gets the integer. + * + * @return the integer + */ + public BigInteger getValue(); + + /** + * Sets the integer. + * + * @param newValue the integer value + */ + public void setValue(BigInteger newValue); + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/X509SubjectName.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/X509SubjectName.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/X509SubjectName.java 17 Aug 2012 15:17:14 -0000 1.1 @@ -0,0 +1,35 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature; + +import javax.xml.namespace.QName; + +import org.opensaml.xml.schema.XSString; +import org.opensaml.xml.util.XMLConstants; + +/** XMLObject representing XML Digital Signature, version 20020212, X509SubjectName element. */ +public interface X509SubjectName extends XSString { + + /** Element local name. */ + public static final String DEFAULT_ELEMENT_LOCAL_NAME = "X509SubjectName"; + + /** Default element name. */ + public static final QName DEFAULT_ELEMENT_NAME = new QName(XMLConstants.XMLSIG_NS, DEFAULT_ELEMENT_LOCAL_NAME, + XMLConstants.XMLSIG_PREFIX); + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/XMLSignatureBuilder.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/XMLSignatureBuilder.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/XMLSignatureBuilder.java 17 Aug 2012 15:17:15 -0000 1.1 @@ -0,0 +1,37 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature; + +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.XMLObjectBuilder; + +/** + * Builder for XMLObjects from {@link org.opensaml.xml.signature} + * + * @param the type of XMLObject being built + */ +public interface XMLSignatureBuilder extends XMLObjectBuilder { + + /** + * Builds an XMLObject using the default name and namespace information provided XML Signature specifications. + * + * @return built XMLObject + */ + public XMLSignatureType buildObject(); + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/XMLSignatureCredentialContext.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/XMLSignatureCredentialContext.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/XMLSignatureCredentialContext.java 17 Aug 2012 15:17:14 -0000 1.1 @@ -0,0 +1,49 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature; + +import org.opensaml.xml.security.credential.CredentialContext; + +/** + * A credential context for credentials resolved from a {@link KeyInfo} that was found in + * in XML Signature {@link Signature} element. + */ +public class XMLSignatureCredentialContext implements CredentialContext { + + /** The Signature element context. */ + private Signature sig; + + /** + * Constructor. + * + * @param signature the signature resolution context + */ + public XMLSignatureCredentialContext(Signature signature) { + sig = signature; + } + + /** + * Gets the Signature element context. + * + * @return signature context + */ + public Signature getSignature() { + return sig; + } + +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/XPath.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/XPath.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/XPath.java 17 Aug 2012 15:17:14 -0000 1.1 @@ -0,0 +1,36 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature; + +import javax.xml.namespace.QName; + +import org.opensaml.xml.schema.XSString; +import org.opensaml.xml.util.XMLConstants; + +/** + * XMLObject representing XML Digital Signature, version 20020212, XPath element. + */ +public interface XPath extends XSString { + + /** Element local name */ + public final static String DEFAULT_ELEMENT_LOCAL_NAME = "XPath"; + + /** Default element name */ + public final static QName DEFAULT_ELEMENT_NAME = new QName(XMLConstants.XMLSIG_NS, DEFAULT_ELEMENT_LOCAL_NAME, XMLConstants.XMLSIG_PREFIX); + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/Y.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/Y.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/Y.java 17 Aug 2012 15:17:15 -0000 1.1 @@ -0,0 +1,36 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature; + +import javax.xml.namespace.QName; + +import org.opensaml.xml.util.XMLConstants; + +/** + * XMLObject representing XML Digital Signature, version 20020212, Y element. + */ +public interface Y extends CryptoBinary { + + /** Element local name */ + public final static String DEFAULT_ELEMENT_LOCAL_NAME = "Y"; + + /** Default element name */ + public final static QName DEFAULT_ELEMENT_NAME = new QName(XMLConstants.XMLSIG_NS, DEFAULT_ELEMENT_LOCAL_NAME, XMLConstants.XMLSIG_PREFIX); + + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/package.html =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/package.html,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/package.html 17 Aug 2012 15:17:14 -0000 1.1 @@ -0,0 +1,9 @@ + + +XMLObject interfaces and helper classes for representing digitally signed content and signing/validating content. + +

+Those classes starting with XMLSec use the Apache XML Security library +to provide their functionality. Support for the JSR-105 will be added in the future. + + \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/AbstractXMLSignatureMarshaller.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/AbstractXMLSignatureMarshaller.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/AbstractXMLSignatureMarshaller.java 17 Aug 2012 15:17:03 -0000 1.1 @@ -0,0 +1,49 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature.impl; + +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.io.AbstractXMLObjectMarshaller; +import org.opensaml.xml.io.MarshallingException; +import org.w3c.dom.Element; + +/** + * An abstract marshaller implementation for XMLObjects from {@link org.opensaml.xml.signature}. + */ +public abstract class AbstractXMLSignatureMarshaller extends AbstractXMLObjectMarshaller { + + /** + * No-op method. Extending implementations should override this method if they have attributes to marshall into the + * Element. + * + * {@inheritDoc} + */ + protected void marshallAttributes(XMLObject xmlObject, Element domElement) throws MarshallingException { + + } + + /** + * No-op method. Extending implementations should override this method if they have text content to marshall into + * the Element. + * + * {@inheritDoc} + */ + protected void marshallElementContent(XMLObject xmlObject, Element domElement) throws MarshallingException { + + } +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/AbstractXMLSignatureUnmarshaller.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/AbstractXMLSignatureUnmarshaller.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/AbstractXMLSignatureUnmarshaller.java 17 Aug 2012 15:17:03 -0000 1.1 @@ -0,0 +1,58 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature.impl; + +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.io.AbstractXMLObjectUnmarshaller; +import org.opensaml.xml.io.UnmarshallingException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.w3c.dom.Attr; + +/** + * An abstract unmarshaller implementation for XMLObjects from {@link org.opensaml.xml.signature}. + */ +public abstract class AbstractXMLSignatureUnmarshaller extends AbstractXMLObjectUnmarshaller { + + /** + * Logger. + */ + private final Logger log = LoggerFactory.getLogger(AbstractXMLSignatureUnmarshaller.class); + + /** + * {@inheritDoc} + */ + protected void processChildElement(XMLObject parentXMLObject, XMLObject childXMLObject) + throws UnmarshallingException { + log.debug("Ignoring unknown element {}", childXMLObject.getElementQName()); + } + + /** + * {@inheritDoc} + */ + protected void processAttribute(XMLObject xmlObject, Attr attribute) throws UnmarshallingException { + log.debug("Ignorning unknown attribute {}", attribute.getLocalName()); + } + + /** + * {@inheritDoc} + */ + protected void processElementContent(XMLObject xmlObject, String elementContent) { + log.debug("Ignoring element content {}", elementContent); + } +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/BaseSignatureTrustEngine.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/BaseSignatureTrustEngine.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/BaseSignatureTrustEngine.java 17 Aug 2012 15:17:02 -0000 1.1 @@ -0,0 +1,201 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature.impl; + +import org.opensaml.xml.security.CriteriaSet; +import org.opensaml.xml.security.SecurityException; +import org.opensaml.xml.security.credential.Credential; +import org.opensaml.xml.security.keyinfo.KeyInfoCredentialResolver; +import org.opensaml.xml.security.keyinfo.KeyInfoCriteria; +import org.opensaml.xml.signature.Signature; +import org.opensaml.xml.signature.SignatureTrustEngine; +import org.opensaml.xml.signature.SignatureValidator; +import org.opensaml.xml.util.DatatypeHelper; +import org.opensaml.xml.validation.ValidationException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * A base implementation of {@link SignatureTrustEngine} which evaluates the validity and trustworthiness of XML and raw + * signatures. + * + *

+ * When processing XML signatures, the supplied KeyInfoCredentialResolver will be used to resolve credential(s) + * containing the (advisory) signing key from the KeyInfo element of the Signature, if present. If any of these + * credentials do contain the valid signing key, they will be evaluated for trustworthiness against trusted information, + * which will be resolved in an implementation-specific manner. + * + *

+ * Subclasses are required to implement {@link #evaluateTrust(Credential, Object)} using an implementation-specific + * trust model. + *

+ * + * @param the type of trusted information which has been resolved and which will serve as the basis for + * trust evaluation + * + */ +public abstract class BaseSignatureTrustEngine implements SignatureTrustEngine { + + /** Class logger. */ + private final Logger log = LoggerFactory.getLogger(BaseSignatureTrustEngine.class); + + /** KeyInfo credential resolver used to obtain the signing credential from a Signature's KeyInfo. */ + private KeyInfoCredentialResolver keyInfoCredentialResolver; + + /** + * Constructor. + * + * @param keyInfoResolver KeyInfo credential resolver used to obtain the (advisory) signing credential from a + * Signature's KeyInfo element. + */ + public BaseSignatureTrustEngine(KeyInfoCredentialResolver keyInfoResolver) { + if (keyInfoResolver == null) { + throw new IllegalArgumentException("KeyInfo credential resolver may not be null"); + } + + keyInfoCredentialResolver = keyInfoResolver; + } + + /** {@inheritDoc} */ + public KeyInfoCredentialResolver getKeyInfoResolver() { + return keyInfoCredentialResolver; + } + + /** + * Attempt to establish trust by resolving signature verification credentials from the Signature's KeyInfo. If any + * credentials so resolved correctly verify the signature, attempt to establish trust using subclass-specific trust + * logic against trusted information as implemented in {@link #evaluateTrust(Credential, Object)}. + * + * @param signature the Signature to evaluate + * @param trustBasis the information which serves as the basis for trust evaluation + * @return true if the signature is verified by any KeyInfo-derived credential which can be established as trusted, + * otherwise false + * @throws SecurityException if an error occurs during signature verification or trust processing + */ + protected boolean validate(Signature signature, TrustBasisType trustBasis) throws SecurityException { + + log.debug("Attempting to verify signature and establish trust using KeyInfo-derived credentials"); + + if (signature.getKeyInfo() != null) { + + KeyInfoCriteria keyInfoCriteria = new KeyInfoCriteria(signature.getKeyInfo()); + CriteriaSet keyInfoCriteriaSet = new CriteriaSet(keyInfoCriteria); + + for (Credential kiCred : getKeyInfoResolver().resolve(keyInfoCriteriaSet)) { + if (verifySignature(signature, kiCred)) { + log.debug("Successfully verified signature using KeyInfo-derived credential"); + log.debug("Attempting to establish trust of KeyInfo-derived credential"); + if (evaluateTrust(kiCred, trustBasis)) { + log.debug("Successfully established trust of KeyInfo-derived credential"); + return true; + } else { + log.debug("Failed to establish trust of KeyInfo-derived credential"); + } + } + } + } else { + log.debug("Signature contained no KeyInfo element, could not resolve verification credentials"); + } + + log.debug("Failed to verify signature and/or establish trust using any KeyInfo-derived credentials"); + return false; + } + + /** + * Evaluate the untrusted KeyInfo-derived credential with respect to the specified trusted information. + * + * @param untrustedCredential the untrusted credential being evaluated + * @param trustBasis the information which serves as the basis for trust evaluation + * + * @return true if the trust can be established for the untrusted credential, otherwise false + * + * @throws SecurityException if an error occurs during trust processing + */ + protected abstract boolean evaluateTrust(Credential untrustedCredential, TrustBasisType trustBasis) + throws SecurityException; + + /** + * Attempt to verify a signature using the key from the supplied credential. + * + * @param signature the signature on which to attempt verification + * @param credential the credential containing the candidate validation key + * @return true if the signature can be verified using the key from the credential, otherwise false + */ + protected boolean verifySignature(Signature signature, Credential credential) { + SignatureValidator validator = new SignatureValidator(credential); + try { + validator.validate(signature); + } catch (ValidationException e) { + log.debug("Signature validation using candidate validation credential failed", e); + return false; + } + + log.debug("Signature validation using candidate credential was successful"); + return true; + } + + /** + * Check the signature and credential criteria for required values. + * + * @param signature the signature to be evaluated + * @param trustBasisCriteria the set of trusted credential criteria + * @throws SecurityException thrown if required values are absent or otherwise invalid + */ + protected void checkParams(Signature signature, CriteriaSet trustBasisCriteria) throws SecurityException { + + if (signature == null) { + throw new SecurityException("Signature was null"); + } + if (trustBasisCriteria == null) { + throw new SecurityException("Trust basis criteria set was null"); + } + if (trustBasisCriteria.isEmpty()) { + throw new SecurityException("Trust basis criteria set was empty"); + } + } + + /** + * Check the signature and credential criteria for required values. + * + * @param signature the signature to be evaluated + * @param content the data over which the signature was computed + * @param algorithmURI the signing algorithm URI which was used + * @param trustBasisCriteria the set of trusted credential criteria + * @throws SecurityException thrown if required values are absent or otherwise invalid + */ + protected void checkParamsRaw(byte[] signature, byte[] content, String algorithmURI, CriteriaSet trustBasisCriteria) + throws SecurityException { + + if (signature == null || signature.length == 0) { + throw new SecurityException("Signature byte array was null or empty"); + } + if (content == null || content.length == 0) { + throw new SecurityException("Content byte array was null or empty"); + } + if (DatatypeHelper.isEmpty(algorithmURI)) { + throw new SecurityException("Signature algorithm was null or empty"); + } + if (trustBasisCriteria == null) { + throw new SecurityException("Trust basis criteria set was null"); + } + if (trustBasisCriteria.isEmpty()) { + throw new SecurityException("Trust basis criteria set was empty"); + } + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/ChainingSignatureTrustEngine.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/ChainingSignatureTrustEngine.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/ChainingSignatureTrustEngine.java 17 Aug 2012 15:17:03 -0000 1.1 @@ -0,0 +1,88 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature.impl; + +import java.util.ArrayList; +import java.util.List; + +import org.opensaml.xml.security.CriteriaSet; +import org.opensaml.xml.security.SecurityException; +import org.opensaml.xml.security.credential.Credential; +import org.opensaml.xml.security.keyinfo.KeyInfoCredentialResolver; +import org.opensaml.xml.signature.Signature; +import org.opensaml.xml.signature.SignatureTrustEngine; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Evaluate a signature in sequence using a chain of subordinate trust engines. If the signature may be established as + * trusted by any of the subordinate engines, the token is considered trusted. Otherwise it is considered untrusted. + * + */ +public class ChainingSignatureTrustEngine implements SignatureTrustEngine { + + /** Class logger. */ + private final Logger log = LoggerFactory.getLogger(ChainingSignatureTrustEngine.class); + + /** The chain of subordinate trust engines. */ + private List engines; + + /** Constructor. */ + public ChainingSignatureTrustEngine() { + engines = new ArrayList(); + } + + /** + * Get the list of configured trust engines which constitute the trust evaluation chain. + * + * @return the modifiable list of trust engines in the chain + */ + public List getChain() { + return engines; + } + + /** {@inheritDoc} */ + public KeyInfoCredentialResolver getKeyInfoResolver() { + // Chaining signature trust engine does not support an attached KeyInfoResolver + return null; + } + + /** {@inheritDoc} */ + public boolean validate(Signature token, CriteriaSet trustBasisCriteria) throws SecurityException { + for (SignatureTrustEngine engine : engines) { + if (engine.validate(token, trustBasisCriteria)) { + log.debug("Signature was trusted by chain member: {}", engine.getClass().getName()); + return true; + } + } + return false; + } + + /** {@inheritDoc} */ + public boolean validate(byte[] signature, byte[] content, String algorithmURI, CriteriaSet trustBasisCriteria, + Credential candidateCredential) throws SecurityException { + for (SignatureTrustEngine engine : engines) { + if (engine.validate(signature, content, algorithmURI, trustBasisCriteria, candidateCredential)) { + log.debug("Signature was trusted by chain member: {}", engine.getClass().getName()); + return true; + } + } + return false; + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/CryptoBinaryBuilder.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/CryptoBinaryBuilder.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/CryptoBinaryBuilder.java 17 Aug 2012 15:17:01 -0000 1.1 @@ -0,0 +1,42 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature.impl; + +import org.opensaml.xml.AbstractXMLObjectBuilder; +import org.opensaml.xml.XMLObjectBuilder; +import org.opensaml.xml.signature.CryptoBinary; + +/** + * Builder of {@link org.opensaml.xml.signature.CryptoBinary}. + */ +public class CryptoBinaryBuilder extends AbstractXMLObjectBuilder + implements XMLObjectBuilder{ + + /** + * Constructor. + * + */ + public CryptoBinaryBuilder() { + } + + /** {@inheritDoc} */ + public CryptoBinary buildObject(String namespaceURI, String localName, String namespacePrefix) { + return new CryptoBinaryImpl(namespaceURI, localName, namespacePrefix); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/CryptoBinaryImpl.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/CryptoBinaryImpl.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/CryptoBinaryImpl.java 17 Aug 2012 15:17:02 -0000 1.1 @@ -0,0 +1,75 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature.impl; + +import java.math.BigInteger; + +import org.opensaml.xml.schema.impl.XSBase64BinaryImpl; +import org.opensaml.xml.security.keyinfo.KeyInfoHelper; +import org.opensaml.xml.signature.CryptoBinary; +import org.opensaml.xml.util.DatatypeHelper; + +/** + * Concrete implementation of {@link org.opensaml.xml.signature.CryptoBinary}. + */ +public class CryptoBinaryImpl extends XSBase64BinaryImpl implements CryptoBinary { + + /** The cached BigInteger representation of the element's base64-encoded value. */ + private BigInteger bigIntValue; + + /** + * Constructor. + * + * @param namespaceURI + * @param elementLocalName + * @param namespacePrefix + */ + protected CryptoBinaryImpl(String namespaceURI, String elementLocalName, String namespacePrefix) { + super(namespaceURI, elementLocalName, namespacePrefix); + } + + /** {@inheritDoc} */ + public BigInteger getValueBigInt() { + if (bigIntValue == null && !DatatypeHelper.isEmpty(getValue())) { + bigIntValue = KeyInfoHelper.decodeBigIntegerFromCryptoBinary(getValue()); + } + return bigIntValue; + } + + /** {@inheritDoc} */ + public void setValueBigInt(BigInteger bigInt) { + if (bigInt == null) { + setValue(null); + } else { + setValue(KeyInfoHelper.encodeCryptoBinaryFromBigInteger(bigInt)); + } + bigIntValue = bigInt; + } + + /** {@inheritDoc} */ + public void setValue(String newValue) { + if (bigIntValue != null + && (!DatatypeHelper.safeEquals(getValue(), newValue) || newValue == null)) { + // Just clear the cached value, my not be needed in big int form again, + // let it be lazily recreated if necessary + bigIntValue = null; + } + super.setValue(newValue); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/CryptoBinaryMarshaller.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/CryptoBinaryMarshaller.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/CryptoBinaryMarshaller.java 17 Aug 2012 15:17:00 -0000 1.1 @@ -0,0 +1,28 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature.impl; + +import org.opensaml.xml.schema.impl.XSBase64BinaryMarshaller; + +/** + * A thread-safe Marshaller for {@link org.opensaml.xml.signature.CryptoBinary} objects. + */ +public class CryptoBinaryMarshaller extends XSBase64BinaryMarshaller { + + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/CryptoBinaryUnmarshaller.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/CryptoBinaryUnmarshaller.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/CryptoBinaryUnmarshaller.java 17 Aug 2012 15:17:02 -0000 1.1 @@ -0,0 +1,27 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature.impl; + +import org.opensaml.xml.schema.impl.XSBase64BinaryUnmarshaller; + +/** + * A thread-safe Unmarshaller for {@link org.opensaml.xml.signature.CryptoBinary} objects. + */ +public class CryptoBinaryUnmarshaller extends XSBase64BinaryUnmarshaller { + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/DSAKeyValueBuilder.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/DSAKeyValueBuilder.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/DSAKeyValueBuilder.java 17 Aug 2012 15:17:03 -0000 1.1 @@ -0,0 +1,47 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature.impl; + +import org.opensaml.xml.AbstractXMLObjectBuilder; +import org.opensaml.xml.signature.DSAKeyValue; +import org.opensaml.xml.signature.XMLSignatureBuilder; +import org.opensaml.xml.util.XMLConstants; + +/** + * Builder of {@link org.opensaml.xml.signature.DSAKeyValue} + */ +public class DSAKeyValueBuilder extends AbstractXMLObjectBuilder implements XMLSignatureBuilder { + + /** + * Constructor + * + */ + public DSAKeyValueBuilder() { + } + + /** {@inheritDoc} */ + public DSAKeyValue buildObject(String namespaceURI, String localName, String namespacePrefix) { + return new DSAKeyValueImpl(namespaceURI, localName, namespacePrefix); + } + + /** {@inheritDoc} */ + public DSAKeyValue buildObject() { + return buildObject(XMLConstants.XMLSIG_NS, DSAKeyValue.DEFAULT_ELEMENT_LOCAL_NAME, XMLConstants.XMLSIG_PREFIX); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/DSAKeyValueImpl.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/DSAKeyValueImpl.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/DSAKeyValueImpl.java 17 Aug 2012 15:17:02 -0000 1.1 @@ -0,0 +1,175 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature.impl; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.signature.DSAKeyValue; +import org.opensaml.xml.signature.G; +import org.opensaml.xml.signature.J; +import org.opensaml.xml.signature.P; +import org.opensaml.xml.signature.PgenCounter; +import org.opensaml.xml.signature.Q; +import org.opensaml.xml.signature.Seed; +import org.opensaml.xml.signature.Y; +import org.opensaml.xml.validation.AbstractValidatingXMLObject; + +/** + * Concrete implementation of {@link org.opensaml.xml.signature.DSAKeyValue} + */ +public class DSAKeyValueImpl extends AbstractValidatingXMLObject implements DSAKeyValue { + + /** P child element */ + private P p; + + /** Q child element */ + private Q q; + + /** G child element */ + private G g; + + /** Y child element */ + private Y y; + + /** J child element */ + private J j; + + /** Seed child element */ + private Seed seed; + + /** PgenCounter child element */ + private PgenCounter pgenCounter; + + /** + * Constructor + * + * @param namespaceURI + * @param elementLocalName + * @param namespacePrefix + */ + protected DSAKeyValueImpl(String namespaceURI, String elementLocalName, String namespacePrefix) { + super(namespaceURI, elementLocalName, namespacePrefix); + } + + /** {@inheritDoc} */ + public P getP() { + return this.p; + } + + /** {@inheritDoc} */ + public void setP(P newP) { + this.p = prepareForAssignment(this.p, newP); + } + + /** {@inheritDoc} */ + public Q getQ() { + return this.q; + } + + /** {@inheritDoc} */ + public void setQ(Q newQ) { + this.q = prepareForAssignment(this.q, newQ); + } + + /** {@inheritDoc} */ + public G getG() { + return this.g; + } + + /** {@inheritDoc} */ + public void setG(G newG) { + this.g = prepareForAssignment(this.g, newG); + } + + /** {@inheritDoc} */ + public Y getY() { + return this.y; + } + + /** {@inheritDoc} */ + public void setY(Y newY) { + this.y = prepareForAssignment(this.y, newY); + } + + /** {@inheritDoc} */ + public J getJ() { + return this.j; + } + + /** {@inheritDoc} */ + public void setJ(J newJ) { + this.j = prepareForAssignment(this.j, newJ); + } + + /** {@inheritDoc} */ + public Seed getSeed() { + return this.seed; + } + + /** {@inheritDoc} */ + public void setSeed(Seed newSeed) { + this.seed = prepareForAssignment(this.seed, newSeed); + } + + /** {@inheritDoc} */ + public PgenCounter getPgenCounter() { + return this.pgenCounter; + } + + /** {@inheritDoc} */ + public void setPgenCounter(PgenCounter newPgenCounter) { + this.pgenCounter = prepareForAssignment(this.pgenCounter, newPgenCounter); + } + + /** {@inheritDoc} */ + public List getOrderedChildren() { + ArrayList children = new ArrayList(); + + if (p != null) { + children.add(p); + } + if (q!= null) { + children.add(q); + } + if (g != null) { + children.add(g); + } + if (y != null) { + children.add(y); + } + if (j != null) { + children.add(j); + } + if (seed!= null) { + children.add(seed); + } + if (pgenCounter != null) { + children.add(pgenCounter); + } + + if (children.size() == 0) { + return null; + } + + return Collections.unmodifiableList(children); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/DSAKeyValueMarshaller.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/DSAKeyValueMarshaller.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/DSAKeyValueMarshaller.java 17 Aug 2012 15:17:00 -0000 1.1 @@ -0,0 +1,25 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature.impl; + +/** + * A thread-safe Marshaller for {@link org.opensaml.xml.signature.DSAKeyValue} objects. + */ +public class DSAKeyValueMarshaller extends AbstractXMLSignatureMarshaller { + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/DSAKeyValueUnmarshaller.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/DSAKeyValueUnmarshaller.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/DSAKeyValueUnmarshaller.java 17 Aug 2012 15:17:03 -0000 1.1 @@ -0,0 +1,60 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature.impl; + +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.io.UnmarshallingException; +import org.opensaml.xml.signature.DSAKeyValue; +import org.opensaml.xml.signature.G; +import org.opensaml.xml.signature.J; +import org.opensaml.xml.signature.P; +import org.opensaml.xml.signature.PgenCounter; +import org.opensaml.xml.signature.Q; +import org.opensaml.xml.signature.Seed; +import org.opensaml.xml.signature.Y; + +/** + * A thread-safe Unmarshaller for {@link org.opensaml.xml.signature.DSAKeyValue} objects. + */ +public class DSAKeyValueUnmarshaller extends AbstractXMLSignatureUnmarshaller { + + /** {@inheritDoc} */ + protected void processChildElement(XMLObject parentXMLObject, XMLObject childXMLObject) + throws UnmarshallingException { + DSAKeyValue keyValue = (DSAKeyValue) parentXMLObject; + + if (childXMLObject instanceof P) { + keyValue.setP((P) childXMLObject); + } else if (childXMLObject instanceof Q) { + keyValue.setQ((Q) childXMLObject); + } else if (childXMLObject instanceof G) { + keyValue.setG((G) childXMLObject); + } else if (childXMLObject instanceof Y) { + keyValue.setY((Y) childXMLObject); + } else if (childXMLObject instanceof J) { + keyValue.setJ((J) childXMLObject); + } else if (childXMLObject instanceof Seed) { + keyValue.setSeed((Seed) childXMLObject); + } else if (childXMLObject instanceof PgenCounter) { + keyValue.setPgenCounter((PgenCounter) childXMLObject); + } else { + super.processChildElement(parentXMLObject, childXMLObject); + } + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/DigestMethodBuilder.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/DigestMethodBuilder.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/DigestMethodBuilder.java 17 Aug 2012 15:17:01 -0000 1.1 @@ -0,0 +1,48 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature.impl; + +import org.opensaml.xml.AbstractXMLObjectBuilder; +import org.opensaml.xml.signature.DigestMethod; +import org.opensaml.xml.signature.XMLSignatureBuilder; +import org.opensaml.xml.util.XMLConstants; + +/** + * Builder of {@link org.opensaml.xml.signature.DigestMethod}. + */ +public class DigestMethodBuilder extends AbstractXMLObjectBuilder + implements XMLSignatureBuilder { + + /** + * Constructor. + * + */ + public DigestMethodBuilder() { + } + + /** {@inheritDoc} */ + public DigestMethod buildObject(String namespaceURI, String localName, String namespacePrefix) { + return new DigestMethodImpl(namespaceURI, localName, namespacePrefix); + } + + /** {@inheritDoc} */ + public DigestMethod buildObject() { + return buildObject(XMLConstants.XMLENC_NS, DigestMethod.DEFAULT_ELEMENT_LOCAL_NAME, XMLConstants.XMLENC_PREFIX); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/DigestMethodImpl.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/DigestMethodImpl.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/DigestMethodImpl.java 17 Aug 2012 15:17:02 -0000 1.1 @@ -0,0 +1,87 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature.impl; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import javax.xml.namespace.QName; + +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.signature.DigestMethod; +import org.opensaml.xml.util.IndexedXMLObjectChildrenList; +import org.opensaml.xml.validation.AbstractValidatingXMLObject; + +/** + * Concrete implementation of {@link org.opensaml.xml.signature.DigestMethod}. + */ +public class DigestMethodImpl extends AbstractValidatingXMLObject implements DigestMethod { + + /** Algorithm attribute value. */ + private String algorithm; + + /** "any" children. */ + private final IndexedXMLObjectChildrenList unknownChildren; + + /** + * Constructor. + * + * @param namespaceURI + * @param elementLocalName + * @param namespacePrefix + */ + protected DigestMethodImpl(String namespaceURI, String elementLocalName, String namespacePrefix) { + super(namespaceURI, elementLocalName, namespacePrefix); + + unknownChildren = new IndexedXMLObjectChildrenList(this); + } + + /** {@inheritDoc} */ + public String getAlgorithm() { + return this.algorithm; + } + + /** {@inheritDoc} */ + public void setAlgorithm(String newAlgorithm) { + this.algorithm = prepareForAssignment(this.algorithm, newAlgorithm); + } + + /** {@inheritDoc} */ + public List getUnknownXMLObjects() { + return this.unknownChildren; + } + /** {@inheritDoc} */ + public List getUnknownXMLObjects(QName typeOrName) { + return (List) unknownChildren.subList(typeOrName); + } + + /** {@inheritDoc} */ + public List getOrderedChildren() { + ArrayList children = new ArrayList(); + + children.addAll(unknownChildren); + + if (children.size() == 0) { + return null; + } + + return Collections.unmodifiableList(children); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/DigestMethodMarshaller.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/DigestMethodMarshaller.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/DigestMethodMarshaller.java 17 Aug 2012 15:17:00 -0000 1.1 @@ -0,0 +1,39 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature.impl; + +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.io.MarshallingException; +import org.opensaml.xml.signature.DigestMethod; +import org.w3c.dom.Element; + +/** + * A thread-safe Marshaller for {@link org.opensaml.xml.signature.DigestMethod} objects. + */ +public class DigestMethodMarshaller extends AbstractXMLSignatureMarshaller { + + /** {@inheritDoc} */ + protected void marshallAttributes(XMLObject xmlObject, Element domElement) throws MarshallingException { + DigestMethod dm = (DigestMethod) xmlObject; + + if (dm.getAlgorithm() != null) { + domElement.setAttributeNS(null, DigestMethod.ALGORITHM_ATTRIB_NAME, dm.getAlgorithm()); + } + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/DigestMethodUnmarshaller.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/DigestMethodUnmarshaller.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/DigestMethodUnmarshaller.java 17 Aug 2012 15:17:00 -0000 1.1 @@ -0,0 +1,48 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature.impl; + +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.io.UnmarshallingException; +import org.opensaml.xml.signature.DigestMethod; +import org.w3c.dom.Attr; + +/** + * A thread-safe Unmarshaller for {@link org.opensaml.xml.signature.DigestMethod} objects. + */ +public class DigestMethodUnmarshaller extends AbstractXMLSignatureUnmarshaller { + + /** {@inheritDoc} */ + protected void processAttribute(XMLObject xmlObject, Attr attribute) throws UnmarshallingException { + DigestMethod dm = (DigestMethod) xmlObject; + + if (attribute.getLocalName().equals(DigestMethod.ALGORITHM_ATTRIB_NAME)) { + dm.setAlgorithm(attribute.getValue()); + } else { + super.processAttribute(xmlObject, attribute); + } + } + + /** {@inheritDoc} */ + protected void processChildElement(XMLObject parentXMLObject, XMLObject childXMLObject) + throws UnmarshallingException { + DigestMethod dm = (DigestMethod) parentXMLObject; + dm.getUnknownXMLObjects().add(childXMLObject); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/ExplicitKeySignatureTrustEngine.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/ExplicitKeySignatureTrustEngine.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/ExplicitKeySignatureTrustEngine.java 17 Aug 2012 15:17:03 -0000 1.1 @@ -0,0 +1,173 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature.impl; + +import org.opensaml.xml.security.CriteriaSet; +import org.opensaml.xml.security.SecurityException; +import org.opensaml.xml.security.SecurityHelper; +import org.opensaml.xml.security.SigningUtil; +import org.opensaml.xml.security.credential.Credential; +import org.opensaml.xml.security.credential.CredentialResolver; +import org.opensaml.xml.security.credential.UsageType; +import org.opensaml.xml.security.criteria.KeyAlgorithmCriteria; +import org.opensaml.xml.security.criteria.UsageCriteria; +import org.opensaml.xml.security.keyinfo.KeyInfoCredentialResolver; +import org.opensaml.xml.security.trust.ExplicitKeyTrustEvaluator; +import org.opensaml.xml.security.trust.TrustedCredentialTrustEngine; +import org.opensaml.xml.signature.Signature; +import org.opensaml.xml.signature.SignatureTrustEngine; +import org.opensaml.xml.util.DatatypeHelper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * An implementation of {@link SignatureTrustEngine} which evaluates the validity and trustworthiness of XML and raw + * signatures. + * + *

+ * Processing is first performed as described in {@link BaseSignatureTrustEngine}. If based on this processing, it is + * determined that the Signature's KeyInfo is not present or does not contain a resolveable valid (and trusted) signing + * key, then all trusted credentials obtained by the trusted credential resolver will be used to attempt to validate the + * signature. + *

+ */ +public class ExplicitKeySignatureTrustEngine extends BaseSignatureTrustEngine> implements + TrustedCredentialTrustEngine { + + /** Class logger. */ + private final Logger log = LoggerFactory.getLogger(ExplicitKeySignatureTrustEngine.class); + + /** Resolver used for resolving trusted credentials. */ + private CredentialResolver credentialResolver; + + /** The external explicit key trust engine to use as a basis for trust in this implementation. */ + private ExplicitKeyTrustEvaluator keyTrust; + + /** + * Constructor. + * + * @param resolver credential resolver used to resolve trusted credentials. + * @param keyInfoResolver KeyInfo credential resolver used to obtain the (advisory) signing credential from a + * Signature's KeyInfo element. + */ + public ExplicitKeySignatureTrustEngine(CredentialResolver resolver, KeyInfoCredentialResolver keyInfoResolver) { + super(keyInfoResolver); + if (resolver == null) { + throw new IllegalArgumentException("Credential resolver may not be null"); + } + credentialResolver = resolver; + + keyTrust = new ExplicitKeyTrustEvaluator(); + } + + /** {@inheritDoc} */ + public CredentialResolver getCredentialResolver() { + return credentialResolver; + } + + /** {@inheritDoc} */ + public boolean validate(Signature signature, CriteriaSet trustBasisCriteria) throws SecurityException { + + checkParams(signature, trustBasisCriteria); + + CriteriaSet criteriaSet = new CriteriaSet(); + criteriaSet.addAll(trustBasisCriteria); + if (!criteriaSet.contains(UsageCriteria.class)) { + criteriaSet.add(new UsageCriteria(UsageType.SIGNING)); + } + String jcaAlgorithm = SecurityHelper.getKeyAlgorithmFromURI(signature.getSignatureAlgorithm()); + if (!DatatypeHelper.isEmpty(jcaAlgorithm)) { + criteriaSet.add(new KeyAlgorithmCriteria(jcaAlgorithm), true); + } + + Iterable trustedCredentials = getCredentialResolver().resolve(criteriaSet); + + if (validate(signature, trustedCredentials)) { + return true; + } + + // If the credentials extracted from Signature's KeyInfo (if any) did not verify the + // signature and/or establish trust, as a fall back attempt to verify the signature with + // the trusted credentials directly. + log.debug("Attempting to verify signature using trusted credentials"); + + for (Credential trustedCredential : trustedCredentials) { + if (verifySignature(signature, trustedCredential)) { + log.debug("Successfully verified signature using resolved trusted credential"); + return true; + } + } + log.debug("Failed to verify signature using either KeyInfo-derived or directly trusted credentials"); + return false; + } + + /** {@inheritDoc} */ + public boolean validate(byte[] signature, byte[] content, String algorithmURI, CriteriaSet trustBasisCriteria, + Credential candidateCredential) throws SecurityException { + + checkParamsRaw(signature, content, algorithmURI, trustBasisCriteria); + + CriteriaSet criteriaSet = new CriteriaSet(); + criteriaSet.addAll(trustBasisCriteria); + if (!criteriaSet.contains(UsageCriteria.class)) { + criteriaSet.add(new UsageCriteria(UsageType.SIGNING)); + } + String jcaAlgorithm = SecurityHelper.getKeyAlgorithmFromURI(algorithmURI); + if (!DatatypeHelper.isEmpty(jcaAlgorithm)) { + criteriaSet.add(new KeyAlgorithmCriteria(jcaAlgorithm), true); + } + + Iterable trustedCredentials = getCredentialResolver().resolve(criteriaSet); + + // First try the optional supplied candidate credential + if (candidateCredential != null) { + if (SigningUtil.verifyWithURI(candidateCredential, algorithmURI, signature, content)) { + log.debug("Successfully verified signature using supplied candidate credential"); + log.debug("Attempting to establish trust of supplied candidate credential"); + if (evaluateTrust(candidateCredential, trustedCredentials)) { + log.debug("Successfully established trust of supplied candidate credential"); + return true; + } else { + log.debug("Failed to establish trust of supplied candidate credential"); + } + } + } + + // If the candidate verification credential did not verify the + // signature and/or establish trust, or if no candidate was supplied, + // as a fall back attempt to verify the signature with the trusted credentials directly. + log.debug("Attempting to verify signature using trusted credentials"); + + for (Credential trustedCredential : trustedCredentials) { + if (SigningUtil.verifyWithURI(trustedCredential, algorithmURI, signature, content)) { + log.debug("Successfully verified signature using resolved trusted credential"); + return true; + } + } + log.debug("Failed to verify signature using either supplied candidate credential" + + " or directly trusted credentials"); + return false; + } + + /** {@inheritDoc} */ + protected boolean evaluateTrust(Credential untrustedCredential, Iterable trustedCredentials) + throws SecurityException { + + return keyTrust.validate(untrustedCredential, trustedCredentials); + } +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/ExponentBuilder.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/ExponentBuilder.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/ExponentBuilder.java 17 Aug 2012 15:17:00 -0000 1.1 @@ -0,0 +1,47 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature.impl; + +import org.opensaml.xml.AbstractXMLObjectBuilder; +import org.opensaml.xml.signature.Exponent; +import org.opensaml.xml.signature.XMLSignatureBuilder; +import org.opensaml.xml.util.XMLConstants; + +/** + * Builder of {@link org.opensaml.xml.signature.Exponent} + */ +public class ExponentBuilder extends AbstractXMLObjectBuilder implements XMLSignatureBuilder { + + /** + * Constructor + * + */ + public ExponentBuilder() { + } + + /** {@inheritDoc} */ + public Exponent buildObject(String namespaceURI, String localName, String namespacePrefix) { + return new ExponentImpl(namespaceURI, localName, namespacePrefix); + } + + /** {@inheritDoc} */ + public Exponent buildObject() { + return buildObject(XMLConstants.XMLSIG_NS, Exponent.DEFAULT_ELEMENT_LOCAL_NAME, XMLConstants.XMLSIG_PREFIX); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/ExponentImpl.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/ExponentImpl.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/ExponentImpl.java 17 Aug 2012 15:17:00 -0000 1.1 @@ -0,0 +1,38 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature.impl; + +import org.opensaml.xml.signature.Exponent; + +/** + * Concrete implementation of {@link org.opensaml.xml.signature.Exponent} + */ +public class ExponentImpl extends CryptoBinaryImpl implements Exponent { + + /** + * Constructor + * + * @param namespaceURI + * @param elementLocalName + * @param namespacePrefix + */ + protected ExponentImpl(String namespaceURI, String elementLocalName, String namespacePrefix) { + super(namespaceURI, elementLocalName, namespacePrefix); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/GBuilder.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/GBuilder.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/GBuilder.java 17 Aug 2012 15:17:02 -0000 1.1 @@ -0,0 +1,47 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature.impl; + +import org.opensaml.xml.AbstractXMLObjectBuilder; +import org.opensaml.xml.signature.G; +import org.opensaml.xml.signature.XMLSignatureBuilder; +import org.opensaml.xml.util.XMLConstants; + +/** + * Builder of {@link org.opensaml.xml.signature.G} + */ +public class GBuilder extends AbstractXMLObjectBuilder implements XMLSignatureBuilder { + + /** + * Constructor + * + */ + public GBuilder() { + } + + /** {@inheritDoc} */ + public G buildObject(String namespaceURI, String localName, String namespacePrefix) { + return new GImpl(namespaceURI, localName, namespacePrefix); + } + + /** {@inheritDoc} */ + public G buildObject() { + return buildObject(XMLConstants.XMLSIG_NS, G.DEFAULT_ELEMENT_LOCAL_NAME, XMLConstants.XMLSIG_PREFIX); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/GImpl.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/GImpl.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/GImpl.java 17 Aug 2012 15:17:01 -0000 1.1 @@ -0,0 +1,38 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature.impl; + +import org.opensaml.xml.signature.G; + +/** + * Concrete implementation of {@link org.opensaml.xml.signature.G} + */ +public class GImpl extends CryptoBinaryImpl implements G { + + /** + * Constructor + * + * @param namespaceURI + * @param elementLocalName + * @param namespacePrefix + */ + protected GImpl(String namespaceURI, String elementLocalName, String namespacePrefix) { + super(namespaceURI, elementLocalName, namespacePrefix); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/JBuilder.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/JBuilder.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/JBuilder.java 17 Aug 2012 15:17:00 -0000 1.1 @@ -0,0 +1,47 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature.impl; + +import org.opensaml.xml.AbstractXMLObjectBuilder; +import org.opensaml.xml.signature.J; +import org.opensaml.xml.signature.XMLSignatureBuilder; +import org.opensaml.xml.util.XMLConstants; + +/** + * Builder of {@link org.opensaml.xml.signature.J} + */ +public class JBuilder extends AbstractXMLObjectBuilder implements XMLSignatureBuilder { + + /** + * Constructor + * + */ + public JBuilder() { + } + + /** {@inheritDoc} */ + public J buildObject(String namespaceURI, String localName, String namespacePrefix) { + return new JImpl(namespaceURI, localName, namespacePrefix); + } + + /** {@inheritDoc} */ + public J buildObject() { + return buildObject(XMLConstants.XMLSIG_NS, J.DEFAULT_ELEMENT_LOCAL_NAME, XMLConstants.XMLSIG_PREFIX); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/JImpl.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/JImpl.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/JImpl.java 17 Aug 2012 15:17:02 -0000 1.1 @@ -0,0 +1,38 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature.impl; + +import org.opensaml.xml.signature.J; + +/** + * Concrete implementation of {@link org.opensaml.xml.signature.J} + */ +public class JImpl extends CryptoBinaryImpl implements J { + + /** + * Constructor + * + * @param namespaceURI + * @param elementLocalName + * @param namespacePrefix + */ + protected JImpl(String namespaceURI, String elementLocalName, String namespacePrefix) { + super(namespaceURI, elementLocalName, namespacePrefix); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/KeyInfoBuilder.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/KeyInfoBuilder.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/KeyInfoBuilder.java 17 Aug 2012 15:17:03 -0000 1.1 @@ -0,0 +1,47 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature.impl; + +import org.opensaml.xml.AbstractXMLObjectBuilder; +import org.opensaml.xml.signature.KeyInfo; +import org.opensaml.xml.signature.XMLSignatureBuilder; +import org.opensaml.xml.util.XMLConstants; + +/** + * Builder of {@link org.opensaml.xml.signature.KeyInfo} + */ +public class KeyInfoBuilder extends AbstractXMLObjectBuilder implements XMLSignatureBuilder { + + /** + * Constructor + * + */ + public KeyInfoBuilder() { + } + + /** {@inheritDoc} */ + public KeyInfo buildObject(String namespaceURI, String localName, String namespacePrefix) { + return new KeyInfoImpl(namespaceURI, localName, namespacePrefix); + } + + /** {@inheritDoc} */ + public KeyInfo buildObject() { + return buildObject(XMLConstants.XMLSIG_NS, KeyInfo.DEFAULT_ELEMENT_LOCAL_NAME, XMLConstants.XMLSIG_PREFIX); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/KeyInfoImpl.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/KeyInfoImpl.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/KeyInfoImpl.java 17 Aug 2012 15:17:00 -0000 1.1 @@ -0,0 +1,38 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature.impl; + +import org.opensaml.xml.signature.KeyInfo; + +/** + * Concrete implementation of {@link org.opensaml.xml.signature.KeyInfo} + */ +public class KeyInfoImpl extends KeyInfoTypeImpl implements KeyInfo { + + /** + * Constructor + * + * @param namespaceURI + * @param elementLocalName + * @param namespacePrefix + */ + protected KeyInfoImpl(String namespaceURI, String elementLocalName, String namespacePrefix) { + super(namespaceURI, elementLocalName, namespacePrefix); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/KeyInfoMarshaller.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/KeyInfoMarshaller.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/KeyInfoMarshaller.java 17 Aug 2012 15:17:01 -0000 1.1 @@ -0,0 +1,25 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature.impl; + +/** + * A thread-safe Marshaller for {@link org.opensaml.xml.signature.KeyInfo} objects. + */ +public class KeyInfoMarshaller extends KeyInfoTypeMarshaller { + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/KeyInfoTypeImpl.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/KeyInfoTypeImpl.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/KeyInfoTypeImpl.java 17 Aug 2012 15:17:03 -0000 1.1 @@ -0,0 +1,143 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature.impl; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import javax.xml.namespace.QName; + +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.encryption.AgreementMethod; +import org.opensaml.xml.encryption.EncryptedKey; +import org.opensaml.xml.signature.KeyInfoType; +import org.opensaml.xml.signature.KeyName; +import org.opensaml.xml.signature.KeyValue; +import org.opensaml.xml.signature.MgmtData; +import org.opensaml.xml.signature.PGPData; +import org.opensaml.xml.signature.RetrievalMethod; +import org.opensaml.xml.signature.SPKIData; +import org.opensaml.xml.signature.X509Data; +import org.opensaml.xml.util.IndexedXMLObjectChildrenList; +import org.opensaml.xml.validation.AbstractValidatingXMLObject; + +/** + * Concrete implementation of {@link org.opensaml.xml.signature.KeyInfoType} + */ +public class KeyInfoTypeImpl extends AbstractValidatingXMLObject implements KeyInfoType { + + /** The list of XMLObject child elements */ + private final IndexedXMLObjectChildrenList indexedChildren; + + /** The Id attribute value */ + private String id; + + /** + * Constructor + * + * @param namespaceURI + * @param elementLocalName + * @param namespacePrefix + */ + protected KeyInfoTypeImpl(String namespaceURI, String elementLocalName, String namespacePrefix) { + super(namespaceURI, elementLocalName, namespacePrefix); + indexedChildren = new IndexedXMLObjectChildrenList(this); + } + + /** {@inheritDoc} */ + public String getID() { + return this.id; + } + + /** {@inheritDoc} */ + public void setID(String newID) { + String oldID = this.id; + this.id = prepareForAssignment(this.id, newID); + registerOwnID(oldID, this.id); + } + + /** {@inheritDoc} */ + public List getXMLObjects() { + return (List) indexedChildren; + } + + /** {@inheritDoc} */ + public List getXMLObjects(QName typeOrName) { + return (List) indexedChildren.subList(typeOrName); + } + + /** {@inheritDoc} */ + public List getKeyNames() { + return (List) indexedChildren.subList(KeyName.DEFAULT_ELEMENT_NAME); + } + + /** {@inheritDoc} */ + public List getKeyValues() { + return (List) indexedChildren.subList(KeyValue.DEFAULT_ELEMENT_NAME); + } + + /** {@inheritDoc} */ + public List getRetrievalMethods() { + return (List) indexedChildren.subList(RetrievalMethod.DEFAULT_ELEMENT_NAME); + } + + /** {@inheritDoc} */ + public List getX509Datas() { + return (List) indexedChildren.subList(X509Data.DEFAULT_ELEMENT_NAME); + } + + /** {@inheritDoc} */ + public List getPGPDatas() { + return (List) indexedChildren.subList(PGPData.DEFAULT_ELEMENT_NAME); + } + + /** {@inheritDoc} */ + public List getSPKIDatas() { + return (List) indexedChildren.subList(SPKIData.DEFAULT_ELEMENT_NAME); + } + + /** {@inheritDoc} */ + public List getMgmtDatas() { + return (List) indexedChildren.subList(MgmtData.DEFAULT_ELEMENT_NAME); + } + + /** {@inheritDoc} */ + public List getAgreementMethods() { + return (List) indexedChildren.subList(AgreementMethod.DEFAULT_ELEMENT_NAME); + } + + /** {@inheritDoc} */ + public List getEncryptedKeys() { + return (List) indexedChildren.subList(EncryptedKey.DEFAULT_ELEMENT_NAME); + } + + /** {@inheritDoc} */ + public List getOrderedChildren() { + ArrayList children = new ArrayList(); + + children.addAll(indexedChildren); + + if (children.size() == 0) { + return null; + } + + return Collections.unmodifiableList(children); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/KeyInfoTypeMarshaller.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/KeyInfoTypeMarshaller.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/KeyInfoTypeMarshaller.java 17 Aug 2012 15:17:00 -0000 1.1 @@ -0,0 +1,40 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature.impl; + +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.io.MarshallingException; +import org.opensaml.xml.signature.KeyInfoType; +import org.w3c.dom.Element; + +/** + * A thread-safe Marshaller for {@link org.opensaml.xml.signature.KeyInfoType} objects. + */ +public class KeyInfoTypeMarshaller extends AbstractXMLSignatureMarshaller { + + /** {@inheritDoc} */ + protected void marshallAttributes(XMLObject xmlObject, Element domElement) throws MarshallingException { + KeyInfoType keyInfo = (KeyInfoType) xmlObject; + + if (keyInfo.getID() != null) { + domElement.setAttributeNS(null, KeyInfoType.ID_ATTRIB_NAME, keyInfo.getID()); + domElement.setIdAttributeNS(null, KeyInfoType.ID_ATTRIB_NAME, true); + } + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/KeyInfoTypeUnmarshaller.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/KeyInfoTypeUnmarshaller.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/KeyInfoTypeUnmarshaller.java 17 Aug 2012 15:17:02 -0000 1.1 @@ -0,0 +1,53 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature.impl; + +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.io.UnmarshallingException; +import org.opensaml.xml.signature.KeyInfoType; +import org.w3c.dom.Attr; + +/** + * A thread-safe Unmarshaller for {@link org.opensaml.xml.signature.KeyInfoType} objects. + */ +public class KeyInfoTypeUnmarshaller extends AbstractXMLSignatureUnmarshaller { + + /** {@inheritDoc} */ + protected void processAttribute(XMLObject xmlObject, Attr attribute) throws UnmarshallingException { + KeyInfoType keyInfo = (KeyInfoType) xmlObject; + + if (attribute.getLocalName().equals(KeyInfoType.ID_ATTRIB_NAME)) { + keyInfo.setID(attribute.getValue()); + attribute.getOwnerElement().setIdAttributeNode(attribute, true); + } else { + super.processAttribute(xmlObject, attribute); + } + } + + /** {@inheritDoc} */ + protected void processChildElement(XMLObject parentXMLObject, XMLObject childXMLObject) + throws UnmarshallingException { + KeyInfoType keyInfo = (KeyInfoType) parentXMLObject; + + // KeyInfoType contains a range of specific types, but also + // support , with an unbounded choice over all (no ordering) + // so no need to distinguish. + keyInfo.getXMLObjects().add(childXMLObject); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/KeyInfoUnmarshaller.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/KeyInfoUnmarshaller.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/KeyInfoUnmarshaller.java 17 Aug 2012 15:17:02 -0000 1.1 @@ -0,0 +1,23 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature.impl; + +/** Unmarshaller of {@link org.opensaml.xml.signature.KeyInfo} objects. */ +public class KeyInfoUnmarshaller extends KeyInfoTypeUnmarshaller { + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/KeyNameBuilder.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/KeyNameBuilder.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/KeyNameBuilder.java 17 Aug 2012 15:17:00 -0000 1.1 @@ -0,0 +1,47 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature.impl; + +import org.opensaml.xml.AbstractXMLObjectBuilder; +import org.opensaml.xml.signature.KeyName; +import org.opensaml.xml.signature.XMLSignatureBuilder; +import org.opensaml.xml.util.XMLConstants; + +/** + * Builder of {@link org.opensaml.xml.signature.KeyName} + */ +public class KeyNameBuilder extends AbstractXMLObjectBuilder implements XMLSignatureBuilder { + + /** + * Constructor + * + */ + public KeyNameBuilder() { + } + + /** {@inheritDoc} */ + public KeyName buildObject(String namespaceURI, String localName, String namespacePrefix) { + return new KeyNameImpl(namespaceURI, localName, namespacePrefix); + } + + /** {@inheritDoc} */ + public KeyName buildObject() { + return buildObject(XMLConstants.XMLSIG_NS, KeyName.DEFAULT_ELEMENT_LOCAL_NAME, XMLConstants.XMLSIG_PREFIX); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/KeyNameImpl.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/KeyNameImpl.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/KeyNameImpl.java 17 Aug 2012 15:17:00 -0000 1.1 @@ -0,0 +1,39 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature.impl; + +import org.opensaml.xml.schema.impl.XSStringImpl; +import org.opensaml.xml.signature.KeyName; + +/** + * Concrete implementation of {@link org.opensaml.xml.signature.KeyName} + */ +public class KeyNameImpl extends XSStringImpl implements KeyName { + + /** + * Constructor + * + * @param namespaceURI + * @param elementLocalName + * @param namespacePrefix + */ + protected KeyNameImpl(String namespaceURI, String elementLocalName, String namespacePrefix) { + super(namespaceURI, elementLocalName, namespacePrefix); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/KeyValueBuilder.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/KeyValueBuilder.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/KeyValueBuilder.java 17 Aug 2012 15:17:01 -0000 1.1 @@ -0,0 +1,47 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature.impl; + +import org.opensaml.xml.AbstractXMLObjectBuilder; +import org.opensaml.xml.signature.KeyValue; +import org.opensaml.xml.signature.XMLSignatureBuilder; +import org.opensaml.xml.util.XMLConstants; + +/** + * Builder of {@link org.opensaml.xml.signature.KeyValue} + */ +public class KeyValueBuilder extends AbstractXMLObjectBuilder implements XMLSignatureBuilder { + + /** + * Constructor + * + */ + public KeyValueBuilder() { + } + + /** {@inheritDoc} */ + public KeyValue buildObject(String namespaceURI, String localName, String namespacePrefix) { + return new KeyValueImpl(namespaceURI, localName, namespacePrefix); + } + + /** {@inheritDoc} */ + public KeyValue buildObject() { + return buildObject(XMLConstants.XMLSIG_NS, KeyValue.DEFAULT_ELEMENT_LOCAL_NAME, XMLConstants.XMLSIG_PREFIX); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/KeyValueImpl.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/KeyValueImpl.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/KeyValueImpl.java 17 Aug 2012 15:17:03 -0000 1.1 @@ -0,0 +1,106 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature.impl; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.signature.DSAKeyValue; +import org.opensaml.xml.signature.KeyValue; +import org.opensaml.xml.signature.RSAKeyValue; +import org.opensaml.xml.validation.AbstractValidatingXMLObject; + +/** + * Concrete implementation of {@link org.opensaml.xml.signature.KeyValue} + */ +public class KeyValueImpl extends AbstractValidatingXMLObject implements KeyValue { + + /** DSAKeyValue child element */ + private DSAKeyValue dsaKeyValue; + + /** RSAKeyValue child element */ + private RSAKeyValue rsaKeyValue; + + /** Wildcard <any> XMLObject child element */ + private XMLObject unknownXMLObject; + + /** + * Constructor + * + * @param namespaceURI + * @param elementLocalName + * @param namespacePrefix + */ + protected KeyValueImpl(String namespaceURI, String elementLocalName, String namespacePrefix) { + super(namespaceURI, elementLocalName, namespacePrefix); + } + + /** {@inheritDoc} */ + public DSAKeyValue getDSAKeyValue() { + return this.dsaKeyValue; + } + + /** {@inheritDoc} */ + public void setDSAKeyValue(DSAKeyValue newDSAKeyValue) { + this.dsaKeyValue = prepareForAssignment(this.dsaKeyValue, newDSAKeyValue); + } + + /** {@inheritDoc} */ + public RSAKeyValue getRSAKeyValue() { + return this.rsaKeyValue; + } + + /** {@inheritDoc} */ + public void setRSAKeyValue(RSAKeyValue newRSAKeyValue) { + this.rsaKeyValue = prepareForAssignment(this.rsaKeyValue, newRSAKeyValue); + } + + /** {@inheritDoc} */ + public XMLObject getUnknownXMLObject() { + return this.unknownXMLObject; + } + + /** {@inheritDoc} */ + public void setUnknownXMLObject(XMLObject newXMLObject) { + this.unknownXMLObject = prepareForAssignment(this.unknownXMLObject, newXMLObject); + } + + /** {@inheritDoc} */ + public List getOrderedChildren() { + ArrayList children = new ArrayList(); + + if (dsaKeyValue != null) { + children.add(dsaKeyValue); + } + if (rsaKeyValue != null) { + children.add(rsaKeyValue); + } + if (unknownXMLObject != null) { + children.add(unknownXMLObject); + } + + if (children.size() == 0) { + return null; + } + + return Collections.unmodifiableList(children); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/KeyValueMarshaller.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/KeyValueMarshaller.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/KeyValueMarshaller.java 17 Aug 2012 15:17:03 -0000 1.1 @@ -0,0 +1,25 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature.impl; + +/** + * A thread-safe Marshaller for {@link org.opensaml.xml.signature.KeyValue} objects. + */ +public class KeyValueMarshaller extends AbstractXMLSignatureMarshaller { + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/KeyValueUnmarshaller.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/KeyValueUnmarshaller.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/KeyValueUnmarshaller.java 17 Aug 2012 15:17:02 -0000 1.1 @@ -0,0 +1,51 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature.impl; + +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.io.UnmarshallingException; +import org.opensaml.xml.signature.DSAKeyValue; +import org.opensaml.xml.signature.KeyValue; +import org.opensaml.xml.signature.RSAKeyValue; + +/** + * A thread-safe Unmarshaller for {@link org.opensaml.xml.signature.KeyValue} objects. + */ +public class KeyValueUnmarshaller extends AbstractXMLSignatureUnmarshaller { + + /** {@inheritDoc} */ + protected void processChildElement(XMLObject parentXMLObject, XMLObject childXMLObject) + throws UnmarshallingException { + KeyValue keyValue = (KeyValue) parentXMLObject; + + if (childXMLObject instanceof DSAKeyValue) { + keyValue.setDSAKeyValue((DSAKeyValue) childXMLObject); + } else if (childXMLObject instanceof RSAKeyValue) { + keyValue.setRSAKeyValue((RSAKeyValue) childXMLObject); + } else { + // There can be only one... + if (keyValue.getUnknownXMLObject() == null) { + keyValue.setUnknownXMLObject(childXMLObject); + } else { + // If this happens, throw the others up to the parent class to be logged/handled. + super.processChildElement(parentXMLObject, childXMLObject); + } + } + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/MgmtDataBuilder.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/MgmtDataBuilder.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/MgmtDataBuilder.java 17 Aug 2012 15:17:00 -0000 1.1 @@ -0,0 +1,47 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature.impl; + +import org.opensaml.xml.AbstractXMLObjectBuilder; +import org.opensaml.xml.signature.MgmtData; +import org.opensaml.xml.signature.XMLSignatureBuilder; +import org.opensaml.xml.util.XMLConstants; + +/** + * Builder of {@link org.opensaml.xml.signature.MgmtData} + */ +public class MgmtDataBuilder extends AbstractXMLObjectBuilder implements XMLSignatureBuilder { + + /** + * Constructor + * + */ + public MgmtDataBuilder() { + } + + /** {@inheritDoc} */ + public MgmtData buildObject(String namespaceURI, String localName, String namespacePrefix) { + return new MgmtDataImpl(namespaceURI, localName, namespacePrefix); + } + + /** {@inheritDoc} */ + public MgmtData buildObject() { + return buildObject(XMLConstants.XMLSIG_NS, MgmtData.DEFAULT_ELEMENT_LOCAL_NAME, XMLConstants.XMLSIG_PREFIX); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/MgmtDataImpl.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/MgmtDataImpl.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/MgmtDataImpl.java 17 Aug 2012 15:17:01 -0000 1.1 @@ -0,0 +1,39 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature.impl; + +import org.opensaml.xml.schema.impl.XSStringImpl; +import org.opensaml.xml.signature.MgmtData; + +/** + * Concrete implementation of {@link org.opensaml.xml.signature.MgmtData} + */ +public class MgmtDataImpl extends XSStringImpl implements MgmtData { + + /** + * Constructor + * + * @param namespaceURI + * @param elementLocalName + * @param namespacePrefix + */ + protected MgmtDataImpl(String namespaceURI, String elementLocalName, String namespacePrefix) { + super(namespaceURI, elementLocalName, namespacePrefix); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/ModulusBuilder.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/ModulusBuilder.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/ModulusBuilder.java 17 Aug 2012 15:17:02 -0000 1.1 @@ -0,0 +1,47 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature.impl; + +import org.opensaml.xml.AbstractXMLObjectBuilder; +import org.opensaml.xml.signature.Modulus; +import org.opensaml.xml.signature.XMLSignatureBuilder; +import org.opensaml.xml.util.XMLConstants; + +/** + * Builder of {@link org.opensaml.xml.signature.Modulus} + */ +public class ModulusBuilder extends AbstractXMLObjectBuilder implements XMLSignatureBuilder { + + /** + * Constructor + * + */ + public ModulusBuilder() { + } + + /** {@inheritDoc} */ + public Modulus buildObject(String namespaceURI, String localName, String namespacePrefix) { + return new ModulusImpl(namespaceURI, localName, namespacePrefix); + } + + /** {@inheritDoc} */ + public Modulus buildObject() { + return buildObject(XMLConstants.XMLSIG_NS, Modulus.DEFAULT_ELEMENT_LOCAL_NAME, XMLConstants.XMLSIG_PREFIX); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/ModulusImpl.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/ModulusImpl.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/ModulusImpl.java 17 Aug 2012 15:17:01 -0000 1.1 @@ -0,0 +1,38 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature.impl; + +import org.opensaml.xml.signature.Modulus; + +/** + * Concrete implementation of {@link org.opensaml.xml.signature.Exponent} + */ +public class ModulusImpl extends CryptoBinaryImpl implements Modulus { + + /** + * Constructor + * + * @param namespaceURI + * @param elementLocalName + * @param namespacePrefix + */ + protected ModulusImpl(String namespaceURI, String elementLocalName, String namespacePrefix) { + super(namespaceURI, elementLocalName, namespacePrefix); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/PBuilder.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/PBuilder.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/PBuilder.java 17 Aug 2012 15:17:01 -0000 1.1 @@ -0,0 +1,47 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature.impl; + +import org.opensaml.xml.AbstractXMLObjectBuilder; +import org.opensaml.xml.signature.P; +import org.opensaml.xml.signature.XMLSignatureBuilder; +import org.opensaml.xml.util.XMLConstants; + +/** + * Builder of {@link org.opensaml.xml.signature.P} + */ +public class PBuilder extends AbstractXMLObjectBuilder

implements XMLSignatureBuilder

{ + + /** + * Constructor + * + */ + public PBuilder() { + } + + /** {@inheritDoc} */ + public P buildObject(String namespaceURI, String localName, String namespacePrefix) { + return new PImpl(namespaceURI, localName, namespacePrefix); + } + + /** {@inheritDoc} */ + public P buildObject() { + return buildObject(XMLConstants.XMLSIG_NS, P.DEFAULT_ELEMENT_LOCAL_NAME, XMLConstants.XMLSIG_PREFIX); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/PGPDataBuilder.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/PGPDataBuilder.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/PGPDataBuilder.java 17 Aug 2012 15:17:03 -0000 1.1 @@ -0,0 +1,47 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature.impl; + +import org.opensaml.xml.AbstractXMLObjectBuilder; +import org.opensaml.xml.signature.PGPData; +import org.opensaml.xml.signature.XMLSignatureBuilder; +import org.opensaml.xml.util.XMLConstants; + +/** + * Builder of {@link org.opensaml.xml.signature.PGPData} + */ +public class PGPDataBuilder extends AbstractXMLObjectBuilder implements XMLSignatureBuilder { + + /** + * Constructor + * + */ + public PGPDataBuilder() { + } + + /** {@inheritDoc} */ + public PGPData buildObject(String namespaceURI, String localName, String namespacePrefix) { + return new PGPDataImpl(namespaceURI, localName, namespacePrefix); + } + + /** {@inheritDoc} */ + public PGPData buildObject() { + return buildObject(XMLConstants.XMLSIG_NS, PGPData.DEFAULT_ELEMENT_LOCAL_NAME, XMLConstants.XMLSIG_PREFIX); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/PGPDataImpl.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/PGPDataImpl.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/PGPDataImpl.java 17 Aug 2012 15:17:03 -0000 1.1 @@ -0,0 +1,107 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature.impl; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import javax.xml.namespace.QName; + +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.signature.PGPData; +import org.opensaml.xml.signature.PGPKeyID; +import org.opensaml.xml.signature.PGPKeyPacket; +import org.opensaml.xml.util.IndexedXMLObjectChildrenList; +import org.opensaml.xml.validation.AbstractValidatingXMLObject; + +/** + * Concrete implementation of {@link org.opensaml.xml.signature.PGPData} + */ +public class PGPDataImpl extends AbstractValidatingXMLObject implements PGPData { + + /** PGPKeyID child element value */ + private PGPKeyID pgpKeyID; + + /** PGPKeyPacket child element value */ + private PGPKeyPacket pgpKeyPacket; + + /** List of <any> wildcard XMLObject children */ + private final IndexedXMLObjectChildrenList xmlChildren; + + /** + * Constructor + * + * @param namespaceURI + * @param elementLocalName + * @param namespacePrefix + */ + protected PGPDataImpl(String namespaceURI, String elementLocalName, String namespacePrefix) { + super(namespaceURI, elementLocalName, namespacePrefix); + xmlChildren = new IndexedXMLObjectChildrenList(this); + } + + /** {@inheritDoc} */ + public PGPKeyID getPGPKeyID() { + return this.pgpKeyID; + } + + /** {@inheritDoc} */ + public void setPGPKeyID(PGPKeyID newPGPKeyID) { + this.pgpKeyID = prepareForAssignment(this.pgpKeyID, newPGPKeyID); + } + + /** {@inheritDoc} */ + public PGPKeyPacket getPGPKeyPacket() { + return this.pgpKeyPacket; + } + + /** {@inheritDoc} */ + public void setPGPKeyPacket(PGPKeyPacket newPGPKeyPacket) { + this.pgpKeyPacket = prepareForAssignment(this.pgpKeyPacket, newPGPKeyPacket); + } + + /** {@inheritDoc} */ + public List getUnknownXMLObjects() { + return (List) xmlChildren; + } + /** {@inheritDoc} */ + public List getUnknownXMLObjects(QName typeOrName) { + return (List) xmlChildren.subList(typeOrName); + } + + /** {@inheritDoc} */ + public List getOrderedChildren() { + ArrayList children = new ArrayList(); + + if (pgpKeyID != null) { + children.add(pgpKeyID); + } + if (pgpKeyPacket != null) { + children.add(pgpKeyPacket); + } + children.addAll((List) xmlChildren); + + if (children.size() == 0) { + return null; + } + + return Collections.unmodifiableList(children); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/PGPDataMarshaller.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/PGPDataMarshaller.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/PGPDataMarshaller.java 17 Aug 2012 15:17:03 -0000 1.1 @@ -0,0 +1,25 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature.impl; + +/** + * A thread-safe Marshaller for {@link org.opensaml.xml.signature.PGPData} objects. + */ +public class PGPDataMarshaller extends AbstractXMLSignatureMarshaller { + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/PGPDataUnmarshaller.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/PGPDataUnmarshaller.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/PGPDataUnmarshaller.java 17 Aug 2012 15:17:02 -0000 1.1 @@ -0,0 +1,46 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature.impl; + +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.io.UnmarshallingException; +import org.opensaml.xml.signature.PGPData; +import org.opensaml.xml.signature.PGPKeyID; +import org.opensaml.xml.signature.PGPKeyPacket; + +/** + * A thread-safe Unmarshaller for {@link org.opensaml.xml.signature.PGPData} objects. + */ +public class PGPDataUnmarshaller extends AbstractXMLSignatureUnmarshaller { + + /** {@inheritDoc} */ + protected void processChildElement(XMLObject parentXMLObject, XMLObject childXMLObject) + throws UnmarshallingException { + PGPData pgpData = (PGPData) parentXMLObject; + + if (childXMLObject instanceof PGPKeyID) { + pgpData.setPGPKeyID((PGPKeyID) childXMLObject); + } else if (childXMLObject instanceof PGPKeyPacket) { + pgpData.setPGPKeyPacket((PGPKeyPacket) childXMLObject); + } else { + // Unbounded choice of wildcard elements + pgpData.getUnknownXMLObjects().add(childXMLObject); + } + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/PGPKeyIDBuilder.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/PGPKeyIDBuilder.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/PGPKeyIDBuilder.java 17 Aug 2012 15:17:02 -0000 1.1 @@ -0,0 +1,47 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature.impl; + +import org.opensaml.xml.AbstractXMLObjectBuilder; +import org.opensaml.xml.signature.PGPKeyID; +import org.opensaml.xml.signature.XMLSignatureBuilder; +import org.opensaml.xml.util.XMLConstants; + +/** + * Builder of {@link org.opensaml.xml.signature.PGPKeyID} + */ +public class PGPKeyIDBuilder extends AbstractXMLObjectBuilder implements XMLSignatureBuilder { + + /** + * Constructor + * + */ + public PGPKeyIDBuilder() { + } + + /** {@inheritDoc} */ + public PGPKeyID buildObject(String namespaceURI, String localName, String namespacePrefix) { + return new PGPKeyIDImpl(namespaceURI, localName, namespacePrefix); + } + + /** {@inheritDoc} */ + public PGPKeyID buildObject() { + return buildObject(XMLConstants.XMLSIG_NS, PGPKeyID.DEFAULT_ELEMENT_LOCAL_NAME, XMLConstants.XMLSIG_PREFIX); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/PGPKeyIDImpl.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/PGPKeyIDImpl.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/PGPKeyIDImpl.java 17 Aug 2012 15:17:02 -0000 1.1 @@ -0,0 +1,39 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature.impl; + +import org.opensaml.xml.schema.impl.XSBase64BinaryImpl; +import org.opensaml.xml.signature.PGPKeyID; + +/** + * Concrete implementation of {@link org.opensaml.xml.signature.PGPKeyID} + */ +public class PGPKeyIDImpl extends XSBase64BinaryImpl implements PGPKeyID { + + /** + * Constructor + * + * @param namespaceURI + * @param elementLocalName + * @param namespacePrefix + */ + protected PGPKeyIDImpl(String namespaceURI, String elementLocalName, String namespacePrefix) { + super(namespaceURI, elementLocalName, namespacePrefix); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/PGPKeyPacketBuilder.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/PGPKeyPacketBuilder.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/PGPKeyPacketBuilder.java 17 Aug 2012 15:17:01 -0000 1.1 @@ -0,0 +1,47 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature.impl; + +import org.opensaml.xml.AbstractXMLObjectBuilder; +import org.opensaml.xml.signature.PGPKeyPacket; +import org.opensaml.xml.signature.XMLSignatureBuilder; +import org.opensaml.xml.util.XMLConstants; + +/** + * Builder of {@link org.opensaml.xml.signature.PGPKeyPacket} + */ +public class PGPKeyPacketBuilder extends AbstractXMLObjectBuilder implements XMLSignatureBuilder { + + /** + * Constructor + * + */ + public PGPKeyPacketBuilder() { + } + + /** {@inheritDoc} */ + public PGPKeyPacket buildObject(String namespaceURI, String localName, String namespacePrefix) { + return new PGPKeyPacketImpl(namespaceURI, localName, namespacePrefix); + } + + /** {@inheritDoc} */ + public PGPKeyPacket buildObject() { + return buildObject(XMLConstants.XMLSIG_NS, PGPKeyPacket.DEFAULT_ELEMENT_LOCAL_NAME, XMLConstants.XMLSIG_PREFIX); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/PGPKeyPacketImpl.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/PGPKeyPacketImpl.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/PGPKeyPacketImpl.java 17 Aug 2012 15:17:01 -0000 1.1 @@ -0,0 +1,39 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature.impl; + +import org.opensaml.xml.schema.impl.XSBase64BinaryImpl; +import org.opensaml.xml.signature.PGPKeyPacket; + +/** + * Concrete implementation of {@link org.opensaml.xml.signature.PGPKeyPacket} + */ +public class PGPKeyPacketImpl extends XSBase64BinaryImpl implements PGPKeyPacket { + + /** + * Constructor + * + * @param namespaceURI + * @param elementLocalName + * @param namespacePrefix + */ + protected PGPKeyPacketImpl(String namespaceURI, String elementLocalName, String namespacePrefix) { + super(namespaceURI, elementLocalName, namespacePrefix); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/PImpl.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/PImpl.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/PImpl.java 17 Aug 2012 15:17:01 -0000 1.1 @@ -0,0 +1,38 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature.impl; + +import org.opensaml.xml.signature.P; + +/** + * Concrete implementation of {@link org.opensaml.xml.signature.P} + */ +public class PImpl extends CryptoBinaryImpl implements P { + + /** + * Constructor + * + * @param namespaceURI + * @param elementLocalName + * @param namespacePrefix + */ + protected PImpl(String namespaceURI, String elementLocalName, String namespacePrefix) { + super(namespaceURI, elementLocalName, namespacePrefix); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/PKIXSignatureTrustEngine.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/PKIXSignatureTrustEngine.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/PKIXSignatureTrustEngine.java 17 Aug 2012 15:17:02 -0000 1.1 @@ -0,0 +1,281 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature.impl; + +import java.util.Set; + +import org.opensaml.xml.security.CriteriaSet; +import org.opensaml.xml.security.SecurityException; +import org.opensaml.xml.security.SecurityHelper; +import org.opensaml.xml.security.SigningUtil; +import org.opensaml.xml.security.credential.Credential; +import org.opensaml.xml.security.keyinfo.KeyInfoCredentialResolver; +import org.opensaml.xml.security.x509.BasicX509CredentialNameEvaluator; +import org.opensaml.xml.security.x509.PKIXTrustEngine; +import org.opensaml.xml.security.x509.CertPathPKIXTrustEvaluator; +import org.opensaml.xml.security.x509.PKIXTrustEvaluator; +import org.opensaml.xml.security.x509.PKIXValidationInformation; +import org.opensaml.xml.security.x509.PKIXValidationInformationResolver; +import org.opensaml.xml.security.x509.X509Credential; +import org.opensaml.xml.security.x509.X509CredentialNameEvaluator; +import org.opensaml.xml.signature.Signature; +import org.opensaml.xml.signature.SignatureTrustEngine; +import org.opensaml.xml.util.Pair; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * An implementation of {@link SignatureTrustEngine} which evaluates the validity and trustworthiness of XML and raw + * signatures. + * + *

+ * Processing is performed as described in {@link BaseSignatureTrustEngine}. If based on this processing, it is + * determined that the Signature's KeyInfo is not present or does not contain a valid (and trusted) signing key, then + * trust engine validation fails. Since the PKIX engine is based on the assumption that trusted signing keys are not + * known in advance, the signing key must be present in, or derivable from, the information in the Signature's KeyInfo + * element. + *

+ */ +public class PKIXSignatureTrustEngine extends + BaseSignatureTrustEngine, Iterable>> implements + PKIXTrustEngine { + + /** Class logger. */ + private final Logger log = LoggerFactory.getLogger(PKIXSignatureTrustEngine.class); + + /** Resolver used for resolving trusted credentials. */ + private PKIXValidationInformationResolver pkixResolver; + + /** The external PKIX trust evaluator used to establish trust. */ + private PKIXTrustEvaluator pkixTrustEvaluator; + + /** The external credential name evaluator used to establish trusted name compliance. */ + private X509CredentialNameEvaluator credNameEvaluator; + + /** + * Constructor. + * + *

The PKIX trust evaluator used defaults to {@link CertPathPKIXTrustEvaluator}.

+ * + *

The X.509 credential name evaluator used defaults to {@link BasicX509CredentialNameEvaluator}.

+ * + * @param resolver credential resolver used to resolve trusted credentials. + * @param keyInfoResolver KeyInfo credential resolver used to obtain the (advisory) signing credential from a + * Signature's KeyInfo element. + */ + public PKIXSignatureTrustEngine(PKIXValidationInformationResolver resolver, + KeyInfoCredentialResolver keyInfoResolver) { + + super(keyInfoResolver); + if (resolver == null) { + throw new IllegalArgumentException("PKIX trust information resolver may not be null"); + } + pkixResolver = resolver; + + pkixTrustEvaluator = new CertPathPKIXTrustEvaluator(); + credNameEvaluator = new BasicX509CredentialNameEvaluator(); + } + + /** + * Constructor. + * + * @param resolver credential resolver used to resolve trusted credentials. + * @param keyInfoResolver KeyInfo credential resolver used to obtain the (advisory) signing credential from a + * Signature's KeyInfo element. + * * @param pkixEvaluator the PKIX trust evaluator to use + * @param nameEvaluator the X.509 credential name evaluator to use (may be null) + */ + public PKIXSignatureTrustEngine(PKIXValidationInformationResolver resolver, + KeyInfoCredentialResolver keyInfoResolver, PKIXTrustEvaluator pkixEvaluator, + X509CredentialNameEvaluator nameEvaluator) { + + super(keyInfoResolver); + if (resolver == null) { + throw new IllegalArgumentException("PKIX trust information resolver may not be null"); + } + pkixResolver = resolver; + + if (pkixEvaluator == null) { + throw new IllegalArgumentException("PKIX trust evaluator may not be null"); + } + pkixTrustEvaluator = pkixEvaluator; + credNameEvaluator = nameEvaluator; + } + + /** + * Get the PKIXTrustEvaluator instance used to evalute trust. + * + *

The parameters of this evaluator may be modified to + * adjust trust evaluation processing.

+ * + * @return the PKIX trust evaluator instance that will be used + */ + public PKIXTrustEvaluator getPKIXTrustEvaluator() { + return pkixTrustEvaluator; + } + + /** + * Get the X509CredentialNameEvaluator instance used to evalute a credential + * against trusted names. + * + *

The parameters of this evaluator may be modified to + * adjust trust evaluation processing.

+ * + * @return the PKIX trust evaluator instance that will be used + */ + public X509CredentialNameEvaluator getX509CredentialNameEvaluator() { + return credNameEvaluator; + } + + /** {@inheritDoc} */ + public PKIXValidationInformationResolver getPKIXResolver() { + return pkixResolver; + } + + /** {@inheritDoc} */ + public boolean validate(Signature signature, CriteriaSet trustBasisCriteria) throws SecurityException { + + checkParams(signature, trustBasisCriteria); + + Pair, Iterable> validationPair = + resolveValidationInfo(trustBasisCriteria); + + if (validate(signature, validationPair)) { + return true; + } + + log.debug("PKIX validation of signature failed, unable to resolve valid and trusted signing key"); + return false; + } + + /** {@inheritDoc} */ + public boolean validate(byte[] signature, byte[] content, String algorithmURI, CriteriaSet trustBasisCriteria, + Credential candidateCredential) throws SecurityException { + + if (candidateCredential == null || SecurityHelper.extractVerificationKey(candidateCredential) == null) { + log.debug("Candidate credential was either not supplied or did not contain verification key"); + log.debug("PKIX trust engine requires supplied key, skipping PKIX trust evaluation"); + return false; + } + + checkParamsRaw(signature, content, algorithmURI, trustBasisCriteria); + + Pair, Iterable> validationPair = + resolveValidationInfo(trustBasisCriteria); + + if (SigningUtil.verifyWithURI(candidateCredential, algorithmURI, signature, content)) { + log.debug("Successfully verified raw signature using supplied candidate credential"); + log.debug("Attempting to establish trust of supplied candidate credential"); + if (evaluateTrust(candidateCredential, validationPair)) { + log.debug("Successfully established trust of supplied candidate credential"); + return true; + } else { + log.debug("Failed to establish trust of supplied candidate credential"); + } + } else { + log.debug("Cryptographic verification of raw signature failed with candidate credential"); + } + + log.debug("PKIX validation of raw signature failed, " + + "unable to establish trust of supplied verification credential"); + return false; + } + + /** {@inheritDoc} */ + protected boolean evaluateTrust(Credential untrustedCredential, + Pair, Iterable> validationPair) throws SecurityException { + + if (!(untrustedCredential instanceof X509Credential)) { + log.debug("Can not evaluate trust of non-X509Credential"); + return false; + } + X509Credential untrustedX509Credential = (X509Credential) untrustedCredential; + + Set trustedNames = validationPair.getFirst(); + Iterable validationInfoSet = validationPair.getSecond(); + + if (!checkNames(trustedNames, untrustedX509Credential)) { + log.debug("Evaluation of credential against trusted names failed. Aborting PKIX validation"); + return false; + } + + for (PKIXValidationInformation validationInfo : validationInfoSet) { + try { + if (pkixTrustEvaluator.validate(validationInfo, untrustedX509Credential)) { + log.debug("Signature trust established via PKIX validation of signing credential"); + return true; + } + } catch (SecurityException e) { + // log the operational error, but allow other validation info sets to be tried + log.debug("Error performing PKIX validation on untrusted credential", e); + } + } + + log.debug("Signature trust could not be established via PKIX validation of signing credential"); + return false; + } + + /** + * Resolve and return a set of trusted validation information. + * + * @param trustBasisCriteria criteria used to describe and/or resolve the information which serves as the basis for + * trust evaluation + * @return a pair consisting of an optional set of trusted names, and an iterable of trusted + * PKIXValidationInformation + * @throws SecurityException thrown if there is an error resolving the information from the trusted resolver + */ + protected Pair, Iterable> resolveValidationInfo( + CriteriaSet trustBasisCriteria) throws SecurityException { + + Set trustedNames = null; + if (pkixResolver.supportsTrustedNameResolution()) { + trustedNames = pkixResolver.resolveTrustedNames(trustBasisCriteria); + } else { + log.debug("PKIX resolver does not support resolution of trusted names, skipping name checking"); + } + Iterable validationInfoSet = pkixResolver.resolve(trustBasisCriteria); + + Pair, Iterable> validationPair = + new Pair, Iterable>(trustedNames, validationInfoSet); + + return validationPair; + } + + /** + * Evaluate the credential against the set of trusted names. + * + *

Evaluates to true if no intsance of {@link X509CredentialNameEvaluator} is configured.

+ * + * @param trustedNames set of trusted names + * @param untrustedCredential the credential being evaluated + * @return true if evaluation is successful, false otherwise + * @throws SecurityException thrown if there is an error evaluation the credential + */ + protected boolean checkNames(Set trustedNames, X509Credential untrustedCredential) + throws SecurityException { + + if (credNameEvaluator == null) { + log.debug("No credential name evaluator was available, skipping trusted name evaluation"); + return true; + } else { + return credNameEvaluator.evaluate(untrustedCredential, trustedNames); + } + + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/PgenCounterBuilder.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/PgenCounterBuilder.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/PgenCounterBuilder.java 17 Aug 2012 15:17:02 -0000 1.1 @@ -0,0 +1,47 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature.impl; + +import org.opensaml.xml.AbstractXMLObjectBuilder; +import org.opensaml.xml.signature.PgenCounter; +import org.opensaml.xml.signature.XMLSignatureBuilder; +import org.opensaml.xml.util.XMLConstants; + +/** + * Builder of {@link org.opensaml.xml.signature.PgenCounter} + */ +public class PgenCounterBuilder extends AbstractXMLObjectBuilder implements XMLSignatureBuilder { + + /** + * Constructor + * + */ + public PgenCounterBuilder() { + } + + /** {@inheritDoc} */ + public PgenCounter buildObject(String namespaceURI, String localName, String namespacePrefix) { + return new PgenCounterImpl(namespaceURI, localName, namespacePrefix); + } + + /** {@inheritDoc} */ + public PgenCounter buildObject() { + return buildObject(XMLConstants.XMLSIG_NS, PgenCounter.DEFAULT_ELEMENT_LOCAL_NAME, XMLConstants.XMLSIG_PREFIX); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/PgenCounterImpl.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/PgenCounterImpl.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/PgenCounterImpl.java 17 Aug 2012 15:17:00 -0000 1.1 @@ -0,0 +1,38 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature.impl; + +import org.opensaml.xml.signature.PgenCounter; + +/** + * Concrete implementation of {@link org.opensaml.xml.signature.PgenCounter} + */ +public class PgenCounterImpl extends CryptoBinaryImpl implements PgenCounter { + + /** + * Constructor + * + * @param namespaceURI + * @param elementLocalName + * @param namespacePrefix + */ + protected PgenCounterImpl(String namespaceURI, String elementLocalName, String namespacePrefix) { + super(namespaceURI, elementLocalName, namespacePrefix); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/QBuilder.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/QBuilder.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/QBuilder.java 17 Aug 2012 15:17:04 -0000 1.1 @@ -0,0 +1,47 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature.impl; + +import org.opensaml.xml.AbstractXMLObjectBuilder; +import org.opensaml.xml.signature.Q; +import org.opensaml.xml.signature.XMLSignatureBuilder; +import org.opensaml.xml.util.XMLConstants; + +/** + * Builder of {@link org.opensaml.xml.signature.Q} + */ +public class QBuilder extends AbstractXMLObjectBuilder implements XMLSignatureBuilder { + + /** + * Constructor + * + */ + public QBuilder() { + } + + /** {@inheritDoc} */ + public Q buildObject(String namespaceURI, String localName, String namespacePrefix) { + return new QImpl(namespaceURI, localName, namespacePrefix); + } + + /** {@inheritDoc} */ + public Q buildObject() { + return buildObject(XMLConstants.XMLSIG_NS, Q.DEFAULT_ELEMENT_LOCAL_NAME, XMLConstants.XMLSIG_PREFIX); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/QImpl.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/QImpl.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/QImpl.java 17 Aug 2012 15:17:02 -0000 1.1 @@ -0,0 +1,38 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature.impl; + +import org.opensaml.xml.signature.Q; + +/** + * Concrete implementation of {@link org.opensaml.xml.signature.Q} + */ +public class QImpl extends CryptoBinaryImpl implements Q { + + /** + * Constructor + * + * @param namespaceURI + * @param elementLocalName + * @param namespacePrefix + */ + protected QImpl(String namespaceURI, String elementLocalName, String namespacePrefix) { + super(namespaceURI, elementLocalName, namespacePrefix); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/RSAKeyValueBuilder.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/RSAKeyValueBuilder.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/RSAKeyValueBuilder.java 17 Aug 2012 15:17:01 -0000 1.1 @@ -0,0 +1,47 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature.impl; + +import org.opensaml.xml.AbstractXMLObjectBuilder; +import org.opensaml.xml.signature.RSAKeyValue; +import org.opensaml.xml.signature.XMLSignatureBuilder; +import org.opensaml.xml.util.XMLConstants; + +/** + * Builder of {@link org.opensaml.xml.signature.RSAKeyValue} + */ +public class RSAKeyValueBuilder extends AbstractXMLObjectBuilder implements XMLSignatureBuilder { + + /** + * Constructor + * + */ + public RSAKeyValueBuilder() { + } + + /** {@inheritDoc} */ + public RSAKeyValue buildObject(String namespaceURI, String localName, String namespacePrefix) { + return new RSAKeyValueImpl(namespaceURI, localName, namespacePrefix); + } + + /** {@inheritDoc} */ + public RSAKeyValue buildObject() { + return buildObject(XMLConstants.XMLSIG_NS, RSAKeyValue.DEFAULT_ELEMENT_LOCAL_NAME, XMLConstants.XMLSIG_PREFIX); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/RSAKeyValueImpl.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/RSAKeyValueImpl.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/RSAKeyValueImpl.java 17 Aug 2012 15:17:01 -0000 1.1 @@ -0,0 +1,91 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature.impl; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.signature.Exponent; +import org.opensaml.xml.signature.Modulus; +import org.opensaml.xml.signature.RSAKeyValue; +import org.opensaml.xml.validation.AbstractValidatingXMLObject; + +/** + * Concrete implementation of {@link org.opensaml.xml.signature.RSAKeyValue} + */ +public class RSAKeyValueImpl extends AbstractValidatingXMLObject implements RSAKeyValue { + + /** Modulus child element value */ + private Modulus modulus; + + /** Exponent child element value */ + private Exponent exponent; + + /** + * Constructor + * + * @param namespaceURI + * @param elementLocalName + * @param namespacePrefix + */ + protected RSAKeyValueImpl(String namespaceURI, String elementLocalName, String namespacePrefix) { + super(namespaceURI, elementLocalName, namespacePrefix); + } + + /** {@inheritDoc} */ + public Modulus getModulus() { + return this.modulus; + } + + /** {@inheritDoc} */ + public void setModulus(Modulus newModulus) { + this.modulus = prepareForAssignment(this.modulus, newModulus); + } + + /** {@inheritDoc} */ + public Exponent getExponent() { + return this.exponent; + } + + /** {@inheritDoc} */ + public void setExponent(Exponent newExponent) { + this.exponent = prepareForAssignment(this.exponent, newExponent); + + } + + /** {@inheritDoc} */ + public List getOrderedChildren() { + ArrayList children = new ArrayList(); + + if (modulus != null) { + children.add(modulus); + } + if (exponent != null) { + children.add(exponent); + } + + if (children.size() == 0) { + return null; + } + + return Collections.unmodifiableList(children); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/RSAKeyValueMarshaller.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/RSAKeyValueMarshaller.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/RSAKeyValueMarshaller.java 17 Aug 2012 15:17:01 -0000 1.1 @@ -0,0 +1,25 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature.impl; + +/** + * A thread-safe Marshaller for {@link org.opensaml.xml.signature.RSAKeyValue} objects. + */ +public class RSAKeyValueMarshaller extends AbstractXMLSignatureMarshaller { + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/RSAKeyValueUnmarshaller.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/RSAKeyValueUnmarshaller.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/RSAKeyValueUnmarshaller.java 17 Aug 2012 15:17:03 -0000 1.1 @@ -0,0 +1,45 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature.impl; + +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.io.UnmarshallingException; +import org.opensaml.xml.signature.Exponent; +import org.opensaml.xml.signature.Modulus; +import org.opensaml.xml.signature.RSAKeyValue; + +/** + * A thread-safe Unmarshaller for {@link org.opensaml.xml.signature.RSAKeyValue} objects. + */ +public class RSAKeyValueUnmarshaller extends AbstractXMLSignatureUnmarshaller { + + /** {@inheritDoc} */ + protected void processChildElement(XMLObject parentXMLObject, XMLObject childXMLObject) + throws UnmarshallingException { + RSAKeyValue keyValue = (RSAKeyValue) parentXMLObject; + + if (childXMLObject instanceof Modulus) { + keyValue.setModulus((Modulus) childXMLObject); + } else if (childXMLObject instanceof Exponent) { + keyValue.setExponent((Exponent) childXMLObject); + } else { + super.processChildElement(parentXMLObject, childXMLObject); + } + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/RetrievalMethodBuilder.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/RetrievalMethodBuilder.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/RetrievalMethodBuilder.java 17 Aug 2012 15:17:00 -0000 1.1 @@ -0,0 +1,47 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature.impl; + +import org.opensaml.xml.AbstractXMLObjectBuilder; +import org.opensaml.xml.signature.RetrievalMethod; +import org.opensaml.xml.signature.XMLSignatureBuilder; +import org.opensaml.xml.util.XMLConstants; + +/** + * Builder of {@link org.opensaml.xml.signature.RetrievalMethod} + */ +public class RetrievalMethodBuilder extends AbstractXMLObjectBuilder implements XMLSignatureBuilder { + + /** + * Constructor + * + */ + public RetrievalMethodBuilder() { + } + + /** {@inheritDoc} */ + public RetrievalMethod buildObject(String namespaceURI, String localName, String namespacePrefix) { + return new RetrievalMethodImpl(namespaceURI, localName, namespacePrefix); + } + + /** {@inheritDoc} */ + public RetrievalMethod buildObject() { + return buildObject(XMLConstants.XMLSIG_NS, RetrievalMethod.DEFAULT_ELEMENT_LOCAL_NAME, XMLConstants.XMLSIG_PREFIX); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/RetrievalMethodImpl.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/RetrievalMethodImpl.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/RetrievalMethodImpl.java 17 Aug 2012 15:17:02 -0000 1.1 @@ -0,0 +1,99 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature.impl; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.signature.RetrievalMethod; +import org.opensaml.xml.signature.Transforms; +import org.opensaml.xml.validation.AbstractValidatingXMLObject; + +/** + * Concrete implementation of {@link org.opensaml.xml.signature.RetrievalMethod} + */ +public class RetrievalMethodImpl extends AbstractValidatingXMLObject implements RetrievalMethod { + + /** URI attribute value */ + private String uri; + + /** Type attribute value */ + private String type; + + /** Transforms attribute value */ + private Transforms transforms; + + /** + * Constructor + * + * @param namespaceURI + * @param elementLocalName + * @param namespacePrefix + */ + protected RetrievalMethodImpl(String namespaceURI, String elementLocalName, String namespacePrefix) { + super(namespaceURI, elementLocalName, namespacePrefix); + } + + /** {@inheritDoc} */ + public String getURI() { + return this.uri; + } + + /** {@inheritDoc} */ + public void setURI(String newURI) { + this.uri = prepareForAssignment(this.uri, newURI); + } + + /** {@inheritDoc} */ + public String getType() { + return this.type; + } + + /** {@inheritDoc} */ + public void setType(String newType) { + this.type = prepareForAssignment(this.type, newType); + } + + /** {@inheritDoc} */ + public Transforms getTransforms() { + return this.transforms; + } + + /** {@inheritDoc} */ + public void setTransforms(Transforms newTransforms) { + this.transforms = prepareForAssignment(this.transforms, newTransforms); + } + + /** {@inheritDoc} */ + public List getOrderedChildren() { + ArrayList children = new ArrayList(); + + if (transforms != null) { + children.add(transforms); + } + + if (children.size() == 0) { + return null; + } + + return Collections.unmodifiableList(children); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/RetrievalMethodMarshaller.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/RetrievalMethodMarshaller.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/RetrievalMethodMarshaller.java 17 Aug 2012 15:17:02 -0000 1.1 @@ -0,0 +1,42 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature.impl; + +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.io.MarshallingException; +import org.opensaml.xml.signature.RetrievalMethod; +import org.w3c.dom.Element; + +/** + * A thread-safe Marshaller for {@link org.opensaml.xml.signature.RetrievalMethod} objects. + */ +public class RetrievalMethodMarshaller extends AbstractXMLSignatureMarshaller { + + /** {@inheritDoc} */ + protected void marshallAttributes(XMLObject xmlObject, Element domElement) throws MarshallingException { + RetrievalMethod rm = (RetrievalMethod) xmlObject; + + if (rm.getURI() != null) { + domElement.setAttributeNS(null, RetrievalMethod.URI_ATTRIB_NAME, rm.getURI()); + } + if (rm.getType() != null) { + domElement.setAttributeNS(null, RetrievalMethod.TYPE_ATTRIB_NAME, rm.getType()); + } + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/RetrievalMethodUnmarshaller.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/RetrievalMethodUnmarshaller.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/RetrievalMethodUnmarshaller.java 17 Aug 2012 15:17:01 -0000 1.1 @@ -0,0 +1,56 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature.impl; + +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.io.UnmarshallingException; +import org.opensaml.xml.signature.RetrievalMethod; +import org.opensaml.xml.signature.Transforms; +import org.w3c.dom.Attr; + +/** + * A thread-safe Unmarshaller for {@link org.opensaml.xml.signature.RetrievalMethod} objects. + */ +public class RetrievalMethodUnmarshaller extends AbstractXMLSignatureUnmarshaller { + + /** {@inheritDoc} */ + protected void processAttribute(XMLObject xmlObject, Attr attribute) throws UnmarshallingException { + RetrievalMethod rm = (RetrievalMethod) xmlObject; + + if (attribute.getLocalName().equals(RetrievalMethod.URI_ATTRIB_NAME)) { + rm.setURI(attribute.getValue()); + } else if (attribute.getLocalName().equals(RetrievalMethod.TYPE_ATTRIB_NAME)) { + rm.setType(attribute.getValue()); + } else { + super.processAttribute(xmlObject, attribute); + } + } + + /** {@inheritDoc} */ + protected void processChildElement(XMLObject parentXMLObject, XMLObject childXMLObject) + throws UnmarshallingException { + RetrievalMethod rm = (RetrievalMethod) parentXMLObject; + + if (childXMLObject instanceof Transforms) { + rm.setTransforms((Transforms) childXMLObject); + } else { + super.processChildElement(parentXMLObject, childXMLObject); + } + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/SPKIDataBuilder.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/SPKIDataBuilder.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/SPKIDataBuilder.java 17 Aug 2012 15:17:01 -0000 1.1 @@ -0,0 +1,47 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature.impl; + +import org.opensaml.xml.AbstractXMLObjectBuilder; +import org.opensaml.xml.signature.SPKIData; +import org.opensaml.xml.signature.XMLSignatureBuilder; +import org.opensaml.xml.util.XMLConstants; + +/** + * Builder of {@link org.opensaml.xml.signature.SPKIData} + */ +public class SPKIDataBuilder extends AbstractXMLObjectBuilder implements XMLSignatureBuilder { + + /** + * Constructor + * + */ + public SPKIDataBuilder() { + } + + /** {@inheritDoc} */ + public SPKIData buildObject(String namespaceURI, String localName, String namespacePrefix) { + return new SPKIDataImpl(namespaceURI, localName, namespacePrefix); + } + + /** {@inheritDoc} */ + public SPKIData buildObject() { + return buildObject(XMLConstants.XMLSIG_NS, SPKIData.DEFAULT_ELEMENT_LOCAL_NAME, XMLConstants.XMLSIG_PREFIX); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/SPKIDataImpl.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/SPKIDataImpl.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/SPKIDataImpl.java 17 Aug 2012 15:17:03 -0000 1.1 @@ -0,0 +1,80 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature.impl; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import javax.xml.namespace.QName; + +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.signature.SPKIData; +import org.opensaml.xml.signature.SPKISexp; +import org.opensaml.xml.util.IndexedXMLObjectChildrenList; +import org.opensaml.xml.validation.AbstractValidatingXMLObject; + +/** + * Concrete implementation of {@link org.opensaml.xml.signature.SPKIData} + */ +public class SPKIDataImpl extends AbstractValidatingXMLObject implements SPKIData { + + /** The list of XMLObject child elements */ + private final IndexedXMLObjectChildrenList indexedChildren; + + /** + * Constructor + * + * @param namespaceURI + * @param elementLocalName + * @param namespacePrefix + */ + protected SPKIDataImpl(String namespaceURI, String elementLocalName, String namespacePrefix) { + super(namespaceURI, elementLocalName, namespacePrefix); + indexedChildren = new IndexedXMLObjectChildrenList(this); + } + + /** {@inheritDoc} */ + public List getXMLObjects() { + return (List) this.indexedChildren; + } + + /** {@inheritDoc} */ + public List getXMLObjects(QName typeOrName) { + return (List) this.indexedChildren.subList(typeOrName); + } + + /** {@inheritDoc} */ + public List getSPKISexps() { + return (List) this.indexedChildren.subList(SPKISexp.DEFAULT_ELEMENT_NAME); + } + + /** {@inheritDoc} */ + public List getOrderedChildren() { + ArrayList children = new ArrayList(); + + children.addAll((List) indexedChildren); + + if (children.size() == 0) { + return null; + } + + return Collections.unmodifiableList(children); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/SPKIDataMarshaller.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/SPKIDataMarshaller.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/SPKIDataMarshaller.java 17 Aug 2012 15:17:00 -0000 1.1 @@ -0,0 +1,25 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature.impl; + +/** + * A thread-safe Marshaller for {@link org.opensaml.xml.signature.SPKIData} objects. + */ +public class SPKIDataMarshaller extends AbstractXMLSignatureMarshaller { + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/SPKIDataUnmarshaller.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/SPKIDataUnmarshaller.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/SPKIDataUnmarshaller.java 17 Aug 2012 15:17:03 -0000 1.1 @@ -0,0 +1,40 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature.impl; + +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.io.UnmarshallingException; +import org.opensaml.xml.signature.SPKIData; + +/** + * A thread-safe Unmarshaller for {@link org.opensaml.xml.signature.SPKIData} objects. + */ +public class SPKIDataUnmarshaller extends AbstractXMLSignatureUnmarshaller { + + /** {@inheritDoc} */ + protected void processChildElement(XMLObject parentXMLObject, XMLObject childXMLObject) + throws UnmarshallingException { + SPKIData spkiData = (SPKIData) parentXMLObject; + + // SPKIData contains an unbounded sequence of pairs of a single SPKISexp + // and an optional, single wildcard element. Let the Validator + // catch invalid ordering/combinations. + spkiData.getXMLObjects().add(childXMLObject); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/SPKISexpBuilder.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/SPKISexpBuilder.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/SPKISexpBuilder.java 17 Aug 2012 15:17:01 -0000 1.1 @@ -0,0 +1,47 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature.impl; + +import org.opensaml.xml.AbstractXMLObjectBuilder; +import org.opensaml.xml.signature.SPKISexp; +import org.opensaml.xml.signature.XMLSignatureBuilder; +import org.opensaml.xml.util.XMLConstants; + +/** + * Builder of {@link org.opensaml.xml.signature.SPKISexp} + */ +public class SPKISexpBuilder extends AbstractXMLObjectBuilder implements XMLSignatureBuilder { + + /** + * Constructor + * + */ + public SPKISexpBuilder() { + } + + /** {@inheritDoc} */ + public SPKISexp buildObject(String namespaceURI, String localName, String namespacePrefix) { + return new SPKISexpImpl(namespaceURI, localName, namespacePrefix); + } + + /** {@inheritDoc} */ + public SPKISexp buildObject() { + return buildObject(XMLConstants.XMLSIG_NS, SPKISexp.DEFAULT_ELEMENT_LOCAL_NAME, XMLConstants.XMLSIG_PREFIX); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/SPKISexpImpl.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/SPKISexpImpl.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/SPKISexpImpl.java 17 Aug 2012 15:17:04 -0000 1.1 @@ -0,0 +1,39 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature.impl; + +import org.opensaml.xml.schema.impl.XSBase64BinaryImpl; +import org.opensaml.xml.signature.SPKISexp; + +/** + * Concrete implementation of {@link org.opensaml.xml.signature.SPKISexp} + */ +public class SPKISexpImpl extends XSBase64BinaryImpl implements SPKISexp { + + /** + * Constructor + * + * @param namespaceURI + * @param elementLocalName + * @param namespacePrefix + */ + protected SPKISexpImpl(String namespaceURI, String elementLocalName, String namespacePrefix) { + super(namespaceURI, elementLocalName, namespacePrefix); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/SeedBuilder.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/SeedBuilder.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/SeedBuilder.java 17 Aug 2012 15:17:01 -0000 1.1 @@ -0,0 +1,47 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature.impl; + +import org.opensaml.xml.AbstractXMLObjectBuilder; +import org.opensaml.xml.signature.Seed; +import org.opensaml.xml.signature.XMLSignatureBuilder; +import org.opensaml.xml.util.XMLConstants; + +/** + * Builder of {@link org.opensaml.xml.signature.Seed} + */ +public class SeedBuilder extends AbstractXMLObjectBuilder implements XMLSignatureBuilder { + + /** + * Constructor + * + */ + public SeedBuilder() { + } + + /** {@inheritDoc} */ + public Seed buildObject(String namespaceURI, String localName, String namespacePrefix) { + return new SeedImpl(namespaceURI, localName, namespacePrefix); + } + + /** {@inheritDoc} */ + public Seed buildObject() { + return buildObject(XMLConstants.XMLSIG_NS, Seed.DEFAULT_ELEMENT_LOCAL_NAME, XMLConstants.XMLSIG_PREFIX); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/SeedImpl.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/SeedImpl.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/SeedImpl.java 17 Aug 2012 15:17:02 -0000 1.1 @@ -0,0 +1,38 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature.impl; + +import org.opensaml.xml.signature.Seed; + +/** + * Concrete implementation of {@link org.opensaml.xml.signature.Seed} + */ +public class SeedImpl extends CryptoBinaryImpl implements Seed { + + /** + * Constructor + * + * @param namespaceURI + * @param elementLocalName + * @param namespacePrefix + */ + protected SeedImpl(String namespaceURI, String elementLocalName, String namespacePrefix) { + super(namespaceURI, elementLocalName, namespacePrefix); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/SignatureBuilder.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/SignatureBuilder.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/SignatureBuilder.java 17 Aug 2012 15:17:02 -0000 1.1 @@ -0,0 +1,48 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature.impl; + +import org.opensaml.xml.AbstractXMLObjectBuilder; +import org.opensaml.xml.util.XMLConstants; + +/** + * Builder of {@link org.opensaml.xml.signature.Signature}s. + */ +public class SignatureBuilder extends AbstractXMLObjectBuilder { + + /** + * Constructor + */ + public SignatureBuilder() { + + } + + /** + * Creates the XMLObject with the default prefix and local name. + * + * @return the Signature object + */ + public SignatureImpl buildObject() { + return buildObject(XMLConstants.XMLSIG_NS, SignatureImpl.DEFAULT_ELEMENT_LOCAL_NAME, XMLConstants.XMLSIG_PREFIX); + } + + /** {@inheritDoc} */ + public SignatureImpl buildObject(String namespaceURI, String localName, String namespacePrefix) { + return new SignatureImpl(namespaceURI, localName, namespacePrefix); + } +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/SignatureImpl.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/SignatureImpl.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/SignatureImpl.java 17 Aug 2012 15:17:04 -0000 1.1 @@ -0,0 +1,164 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature.impl; + +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; + +import org.apache.xml.security.signature.XMLSignature; +import org.opensaml.xml.AbstractXMLObject; +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.security.credential.Credential; +import org.opensaml.xml.signature.ContentReference; +import org.opensaml.xml.signature.KeyInfo; +import org.opensaml.xml.signature.Signature; + +/** + * XMLObject representing an enveloped or detached XML Digital Signature, version 20020212, Signature element. + */ +public class SignatureImpl extends AbstractXMLObject implements Signature { + + /** Canonicalization algorithm used in signature. */ + private String canonicalizationAlgorithm; + + /** Algorithm used to generate the signature. */ + private String signatureAlgorithm; + + /** Optional HMAC output length parameter to the signature algorithm. */ + private Integer hmacOutputLength; + + /** Key used to sign the signature. */ + private Credential signingCredential; + + /** Public key information to embed in the signature. */ + private KeyInfo keyInfo; + + /** References to content to be signed. */ + private List contentReferences; + + /** Constructed Apache XML Security signature object. */ + private XMLSignature xmlSignature; + + /** + * Constructor. + * + * @param namespaceURI the namespace the element is in + * @param elementLocalName the local name of the XML element this Object represents + * @param namespacePrefix the prefix for the given namespace + */ + protected SignatureImpl(String namespaceURI, String elementLocalName, String namespacePrefix) { + super(namespaceURI, elementLocalName, namespacePrefix); + contentReferences = new LinkedList(); + } + + /** {@inheritDoc} */ + public String getCanonicalizationAlgorithm() { + return canonicalizationAlgorithm; + } + + /** {@inheritDoc} */ + public void setCanonicalizationAlgorithm(String newAlgorithm) { + canonicalizationAlgorithm = prepareForAssignment(canonicalizationAlgorithm, newAlgorithm); + } + + /** {@inheritDoc} */ + public String getSignatureAlgorithm() { + return signatureAlgorithm; + } + + /** {@inheritDoc} */ + public void setSignatureAlgorithm(String newAlgorithm) { + signatureAlgorithm = prepareForAssignment(signatureAlgorithm, newAlgorithm); + } + + /** {@inheritDoc} */ + public Integer getHMACOutputLength() { + return hmacOutputLength; + } + + /** {@inheritDoc} */ + public void setHMACOutputLength(Integer length) { + hmacOutputLength = prepareForAssignment(hmacOutputLength, length); + } + + /** {@inheritDoc} */ + public Credential getSigningCredential() { + return signingCredential; + } + + /** {@inheritDoc} */ + public void setSigningCredential(Credential newCredential) { + signingCredential = prepareForAssignment(signingCredential, newCredential); + } + + /** {@inheritDoc} */ + public KeyInfo getKeyInfo() { + return keyInfo; + } + + /** {@inheritDoc} */ + public void setKeyInfo(KeyInfo newKeyInfo) { + keyInfo = prepareForAssignment(keyInfo, newKeyInfo); + } + + /** {@inheritDoc} */ + public List getContentReferences() { + // TODO worry about detecting changes and releasing this object's and parent's DOM? + // would need something like an Observable list/collection impl or something similar + return contentReferences; + } + + /** {@inheritDoc} */ + public List getOrderedChildren() { + return Collections.EMPTY_LIST; + } + + /** {@inheritDoc} */ + public void releaseDOM() { + super.releaseDOM(); + xmlSignature = null; + + // Signature's does not treat its children as other XMLObjects do + // they are more tightly bound to the Signature and can not exist + // without it. So when Signature releases its DOM it whacks the + // DOM for its children too + if (keyInfo != null) { + keyInfo.releaseChildrenDOM(true); + keyInfo.releaseDOM(); + } + } + + /** + * Get the Apache XML Security signature instance held by this object. + * + * @return an Apache XML Security signature object + */ + public XMLSignature getXMLSignature() { + return xmlSignature; + } + + /** + * Set the Apache XML Security signature instance held by this object. + * + * @param signature an Apache XML Security signature object + */ + public void setXMLSignature(XMLSignature signature) { + xmlSignature = prepareForAssignment(xmlSignature, signature); + } +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/SignatureMarshaller.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/SignatureMarshaller.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/SignatureMarshaller.java 17 Aug 2012 15:17:03 -0000 1.1 @@ -0,0 +1,138 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature.impl; + +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; + +import org.apache.xml.security.Init; +import org.apache.xml.security.exceptions.XMLSecurityException; +import org.apache.xml.security.signature.XMLSignature; +import org.opensaml.xml.Configuration; +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.io.Marshaller; +import org.opensaml.xml.io.MarshallingException; +import org.opensaml.xml.security.SecurityHelper; +import org.opensaml.xml.signature.ContentReference; +import org.opensaml.xml.signature.KeyInfo; +import org.opensaml.xml.signature.Signature; +import org.opensaml.xml.util.XMLHelper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +/** + * A marshaller for {@link org.opensaml.xml.signature.Signature} objects. This marshaller is really a no-op class. All + * the creation of the signature DOM elements is handled by {@link org.opensaml.xml.signature.Signer} when it signs the + * object. + */ +public class SignatureMarshaller implements Marshaller { + + /** Class logger. */ + private final Logger log = LoggerFactory.getLogger(SignatureMarshaller.class); + + /** Constructor. */ + public SignatureMarshaller() { + if (!Init.isInitialized()) { + log.debug("Initializing XML security library"); + Init.init(); + } + } + + /** {@inheritDoc} */ + public Element marshall(XMLObject xmlObject) throws MarshallingException { + try { + Document document = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument(); + return marshall(xmlObject, document); + } catch (ParserConfigurationException e) { + throw new MarshallingException("Unable to create Document to place marshalled elements in", e); + } + } + + /** {@inheritDoc} */ + public Element marshall(XMLObject xmlObject, Element parentElement) throws MarshallingException { + Element signatureElement = createSignatureElement((SignatureImpl) xmlObject, parentElement.getOwnerDocument()); + XMLHelper.appendChildElement(parentElement, signatureElement); + return signatureElement; + } + + /** {@inheritDoc} */ + public Element marshall(XMLObject xmlObject, Document document) throws MarshallingException { + Element signatureElement = createSignatureElement((SignatureImpl) xmlObject, document); + + Element documentRoot = document.getDocumentElement(); + if (documentRoot != null) { + document.replaceChild(signatureElement, documentRoot); + } else { + document.appendChild(signatureElement); + } + + return signatureElement; + } + + /** + * Creates the signature elements but does not compute the signatuer. + * + * @param signature the XMLObject to be signed + * @param document the owning document + * + * @return the Signature element + * + * @throws MarshallingException thrown if the signature can not be constructed + */ + private Element createSignatureElement(Signature signature, Document document) throws MarshallingException { + log.debug("Starting to marshall {}", signature.getElementQName()); + + try { + log.debug("Creating XMLSignature object"); + XMLSignature dsig = null; + if (signature.getHMACOutputLength() != null && SecurityHelper.isHMAC(signature.getSignatureAlgorithm())) { + dsig = new XMLSignature(document, "", signature.getSignatureAlgorithm(), signature + .getHMACOutputLength(), signature.getCanonicalizationAlgorithm()); + } else { + dsig = new XMLSignature(document, "", signature.getSignatureAlgorithm(), signature + .getCanonicalizationAlgorithm()); + } + + log.debug("Adding content to XMLSignature."); + for (ContentReference contentReference : signature.getContentReferences()) { + contentReference.createReference(dsig); + } + + log.debug("Creating Signature DOM element"); + Element signatureElement = dsig.getElement(); + + if (signature.getKeyInfo() != null) { + Marshaller keyInfoMarshaller = Configuration.getMarshallerFactory().getMarshaller( + KeyInfo.DEFAULT_ELEMENT_NAME); + keyInfoMarshaller.marshall(signature.getKeyInfo(), signatureElement); + } + + ((SignatureImpl) signature).setXMLSignature(dsig); + signature.setDOM(signatureElement); + signature.releaseParentDOM(true); + return signatureElement; + + } catch (XMLSecurityException e) { + log.error("Unable to construct signature Element " + signature.getElementQName(), e); + throw new MarshallingException("Unable to construct signature Element " + signature.getElementQName(), e); + } + } + +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/SignatureUnmarshaller.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/SignatureUnmarshaller.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/SignatureUnmarshaller.java 17 Aug 2012 15:17:03 -0000 1.1 @@ -0,0 +1,112 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature.impl; + +import java.util.List; + +import org.apache.xml.security.Init; +import org.apache.xml.security.exceptions.XMLSecurityException; +import org.apache.xml.security.signature.SignedInfo; +import org.apache.xml.security.signature.XMLSignature; +import org.opensaml.xml.Configuration; +import org.opensaml.xml.io.Unmarshaller; +import org.opensaml.xml.io.UnmarshallingException; +import org.opensaml.xml.signature.KeyInfo; +import org.opensaml.xml.signature.Signature; +import org.opensaml.xml.util.DatatypeHelper; +import org.opensaml.xml.util.XMLConstants; +import org.opensaml.xml.util.XMLHelper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.w3c.dom.Element; + +/** + * An unmarshaller for {@link org.opensaml.xml.signature.Signature} objects. + */ +public class SignatureUnmarshaller implements Unmarshaller { + + /** Class logger. */ + private final Logger log = LoggerFactory.getLogger(SignatureUnmarshaller.class); + + /** Constructor. */ + public SignatureUnmarshaller() { + if (!Init.isInitialized()) { + log.debug("Initializing XML security library"); + Init.init(); + } + } + + /** {@inheritDoc} */ + public Signature unmarshall(Element signatureElement) throws UnmarshallingException { + log.debug("Starting to unmarshall Apache XML-Security-based SignatureImpl element"); + + SignatureImpl signature = new SignatureImpl(signatureElement.getNamespaceURI(), + signatureElement.getLocalName(), signatureElement.getPrefix()); + + try { + log.debug("Constructing Apache XMLSignature object"); + + XMLSignature xmlSignature = new XMLSignature(signatureElement, ""); + + SignedInfo signedInfo = xmlSignature.getSignedInfo(); + + log.debug("Adding canonicalization and signing algorithms, and HMAC output length to Signature"); + signature.setCanonicalizationAlgorithm(signedInfo.getCanonicalizationMethodURI()); + signature.setSignatureAlgorithm(signedInfo.getSignatureMethodURI()); + signature.setHMACOutputLength(getHMACOutputLengthValue(signedInfo.getSignatureMethodElement())); + + org.apache.xml.security.keys.KeyInfo xmlSecKeyInfo = xmlSignature.getKeyInfo(); + if (xmlSecKeyInfo != null) { + log.debug("Adding KeyInfo to Signature"); + Unmarshaller unmarshaller = Configuration.getUnmarshallerFactory().getUnmarshaller( + xmlSecKeyInfo.getElement()); + KeyInfo keyInfo = (KeyInfo) unmarshaller.unmarshall(xmlSecKeyInfo.getElement()); + signature.setKeyInfo(keyInfo); + } + signature.setXMLSignature(xmlSignature); + signature.setDOM(signatureElement); + return signature; + } catch (XMLSecurityException e) { + log.error("Error constructing Apache XMLSignature instance from Signature element: {}", e.getMessage()); + throw new UnmarshallingException("Unable to unmarshall Signature with Apache XMLSignature", e); + } + } + + /** + * Find and return the integer value contained within the HMACOutputLength element, if present. + * + * @param signatureMethodElement the ds:SignatureMethod element + * @return the HMAC output length value, or null if not present + */ + private Integer getHMACOutputLengthValue(Element signatureMethodElement) { + if (signatureMethodElement == null) { + return null; + } + // Should be at most one element + List children = XMLHelper.getChildElementsByTagNameNS(signatureMethodElement, XMLConstants.XMLSIG_NS, + "HMACOutputLength"); + if (!children.isEmpty()) { + Element hmacElement = children.get(0); + String value = DatatypeHelper.safeTrimOrNullString(hmacElement.getTextContent()); + if (value != null) { + return new Integer(value); + } + } + return null; + } +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/TransformBuilder.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/TransformBuilder.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/TransformBuilder.java 17 Aug 2012 15:17:01 -0000 1.1 @@ -0,0 +1,47 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature.impl; + +import org.opensaml.xml.AbstractXMLObjectBuilder; +import org.opensaml.xml.signature.Transform; +import org.opensaml.xml.signature.XMLSignatureBuilder; +import org.opensaml.xml.util.XMLConstants; + +/** + * Builder of {@link org.opensaml.xml.signature.Transform} + */ +public class TransformBuilder extends AbstractXMLObjectBuilder implements XMLSignatureBuilder { + + /** + * Constructor + * + */ + public TransformBuilder() { + } + + /** {@inheritDoc} */ + public Transform buildObject(String namespaceURI, String localName, String namespacePrefix) { + return new TransformImpl(namespaceURI, localName, namespacePrefix); + } + + /** {@inheritDoc} */ + public Transform buildObject() { + return buildObject(XMLConstants.XMLSIG_NS, Transform.DEFAULT_ELEMENT_LOCAL_NAME, XMLConstants.XMLSIG_PREFIX); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/TransformImpl.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/TransformImpl.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/TransformImpl.java 17 Aug 2012 15:17:01 -0000 1.1 @@ -0,0 +1,91 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature.impl; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import javax.xml.namespace.QName; + +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.signature.Transform; +import org.opensaml.xml.signature.XPath; +import org.opensaml.xml.util.IndexedXMLObjectChildrenList; +import org.opensaml.xml.validation.AbstractValidatingXMLObject; + +/** + * Concrete implementation of {@link org.opensaml.xml.signature.Transform} + */ +public class TransformImpl extends AbstractValidatingXMLObject implements Transform { + + private String algorithm; + + private final IndexedXMLObjectChildrenList indexedChildren; + + /** + * Constructor + * + * @param namespaceURI + * @param elementLocalName + * @param namespacePrefix + */ + protected TransformImpl(String namespaceURI, String elementLocalName, String namespacePrefix) { + super(namespaceURI, elementLocalName, namespacePrefix); + indexedChildren = new IndexedXMLObjectChildrenList(this); + } + + /** {@inheritDoc} */ + public String getAlgorithm() { + return this.algorithm; + } + + /** {@inheritDoc} */ + public void setAlgorithm(String newAlgorithm) { + this.algorithm = prepareForAssignment(this.algorithm, newAlgorithm); + } + + /** {@inheritDoc} */ + public List getAllChildren() { + return (List) indexedChildren ; + } + + /** {@inheritDoc} */ + public List getXMLObjects(QName typeOrName) { + return (List) indexedChildren.subList(typeOrName); + } + + /** {@inheritDoc} */ + public List getXPaths() { + return (List) indexedChildren.subList(XPath.DEFAULT_ELEMENT_NAME); + } + + /** {@inheritDoc} */ + public List getOrderedChildren() { + ArrayList children = new ArrayList(); + + children.addAll((List) indexedChildren); + + if (children.size() == 0) { + return null; + } + + return Collections.unmodifiableList(children); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/TransformMarshaller.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/TransformMarshaller.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/TransformMarshaller.java 17 Aug 2012 15:17:04 -0000 1.1 @@ -0,0 +1,39 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature.impl; + +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.io.MarshallingException; +import org.opensaml.xml.signature.Transform; +import org.w3c.dom.Element; + +/** + * A thread-safe Marshaller for {@link org.opensaml.xml.signature.Transform} objects. + */ +public class TransformMarshaller extends AbstractXMLSignatureMarshaller { + + /** {@inheritDoc} */ + protected void marshallAttributes(XMLObject xmlObject, Element domElement) throws MarshallingException { + Transform transform = (Transform) xmlObject; + + if (transform.getAlgorithm() != null) { + domElement.setAttributeNS(null, Transform.ALGORITHM_ATTRIB_NAME, transform.getAlgorithm()); + } + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/TransformUnmarshaller.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/TransformUnmarshaller.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/TransformUnmarshaller.java 17 Aug 2012 15:17:03 -0000 1.1 @@ -0,0 +1,50 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature.impl; + +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.io.UnmarshallingException; +import org.opensaml.xml.signature.Transform; +import org.w3c.dom.Attr; + +/** + * A thread-safe Unmarshaller for {@link org.opensaml.xml.signature.Transform} objects. + */ +public class TransformUnmarshaller extends AbstractXMLSignatureUnmarshaller { + + /** {@inheritDoc} */ + protected void processAttribute(XMLObject xmlObject, Attr attribute) throws UnmarshallingException { + Transform transform = (Transform) xmlObject; + + if (attribute.getLocalName().equals(Transform.ALGORITHM_ATTRIB_NAME)) { + transform.setAlgorithm(attribute.getValue()); + } else { + super.processAttribute(xmlObject, attribute); + } + } + + /** {@inheritDoc} */ + protected void processChildElement(XMLObject parentXMLObject, XMLObject childXMLObject) + throws UnmarshallingException { + Transform transform = (Transform) parentXMLObject; + + // Has open content model + XPath children + transform.getAllChildren().add(childXMLObject); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/TransformsBuilder.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/TransformsBuilder.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/TransformsBuilder.java 17 Aug 2012 15:17:03 -0000 1.1 @@ -0,0 +1,47 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature.impl; + +import org.opensaml.xml.AbstractXMLObjectBuilder; +import org.opensaml.xml.signature.Transforms; +import org.opensaml.xml.signature.XMLSignatureBuilder; +import org.opensaml.xml.util.XMLConstants; + +/** + * Builder of {@link org.opensaml.xml.signature.Transforms} + */ +public class TransformsBuilder extends AbstractXMLObjectBuilder implements XMLSignatureBuilder { + + /** + * Constructor + * + */ + public TransformsBuilder() { + } + + /** {@inheritDoc} */ + public Transforms buildObject(String namespaceURI, String localName, String namespacePrefix) { + return new TransformsImpl(namespaceURI, localName, namespacePrefix); + } + + /** {@inheritDoc} */ + public Transforms buildObject() { + return buildObject(XMLConstants.XMLSIG_NS, Transforms.DEFAULT_ELEMENT_LOCAL_NAME, XMLConstants.XMLSIG_PREFIX); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/TransformsImpl.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/TransformsImpl.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/TransformsImpl.java 17 Aug 2012 15:17:03 -0000 1.1 @@ -0,0 +1,67 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature.impl; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.signature.Transform; +import org.opensaml.xml.signature.Transforms; +import org.opensaml.xml.util.XMLObjectChildrenList; +import org.opensaml.xml.validation.AbstractValidatingXMLObject; + +/** + * Concrete implementation of {@link org.opensaml.xml.signature.Transforms} + */ +public class TransformsImpl extends AbstractValidatingXMLObject implements Transforms { + + private final XMLObjectChildrenList transforms; + + /** + * Constructor + * + * @param namespaceURI + * @param elementLocalName + * @param namespacePrefix + */ + protected TransformsImpl(String namespaceURI, String elementLocalName, String namespacePrefix) { + super(namespaceURI, elementLocalName, namespacePrefix); + transforms = new XMLObjectChildrenList(this); + } + + /** {@inheritDoc} */ + public List getTransforms() { + return (List) this.transforms; + } + + /** {@inheritDoc} */ + public List getOrderedChildren() { + ArrayList children = new ArrayList(); + + children.addAll((List) transforms); + + if (children.size() == 0) { + return null; + } + + return Collections.unmodifiableList(children); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/TransformsMarshaller.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/TransformsMarshaller.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/TransformsMarshaller.java 17 Aug 2012 15:17:01 -0000 1.1 @@ -0,0 +1,25 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature.impl; + +/** + * A thread-safe Marshaller for {@link org.opensaml.xml.signature.Transforms} objects. + */ +public class TransformsMarshaller extends AbstractXMLSignatureMarshaller { + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/TransformsUnmarshaller.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/TransformsUnmarshaller.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/TransformsUnmarshaller.java 17 Aug 2012 15:17:03 -0000 1.1 @@ -0,0 +1,42 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature.impl; + +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.io.UnmarshallingException; +import org.opensaml.xml.signature.Transform; +import org.opensaml.xml.signature.Transforms; + +/** + * A thread-safe Unmarshaller for {@link org.opensaml.xml.signature.Transforms} objects. + */ +public class TransformsUnmarshaller extends AbstractXMLSignatureUnmarshaller { + + /** {@inheritDoc} */ + protected void processChildElement(XMLObject parentXMLObject, XMLObject childXMLObject) + throws UnmarshallingException { + Transforms transforms = (Transforms) parentXMLObject; + + if (childXMLObject instanceof Transform) { + transforms.getTransforms().add((Transform) childXMLObject); + } else { + super.processChildElement(parentXMLObject, childXMLObject); + } + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/X509CRLBuilder.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/X509CRLBuilder.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/X509CRLBuilder.java 17 Aug 2012 15:17:02 -0000 1.1 @@ -0,0 +1,47 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature.impl; + +import org.opensaml.xml.AbstractXMLObjectBuilder; +import org.opensaml.xml.signature.X509CRL; +import org.opensaml.xml.signature.XMLSignatureBuilder; +import org.opensaml.xml.util.XMLConstants; + +/** + * Builder of {@link org.opensaml.xml.signature.X509CRL} + */ +public class X509CRLBuilder extends AbstractXMLObjectBuilder implements XMLSignatureBuilder { + + /** + * Constructor + * + */ + public X509CRLBuilder() { + } + + /** {@inheritDoc} */ + public X509CRL buildObject(String namespaceURI, String localName, String namespacePrefix) { + return new X509CRLImpl(namespaceURI, localName, namespacePrefix); + } + + /** {@inheritDoc} */ + public X509CRL buildObject() { + return buildObject(XMLConstants.XMLSIG_NS, X509CRL.DEFAULT_ELEMENT_LOCAL_NAME, XMLConstants.XMLSIG_PREFIX); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/X509CRLImpl.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/X509CRLImpl.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/X509CRLImpl.java 17 Aug 2012 15:17:00 -0000 1.1 @@ -0,0 +1,77 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature.impl; + +import java.util.Collections; +import java.util.List; + +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.signature.X509CRL; +import org.opensaml.xml.util.DatatypeHelper; +import org.opensaml.xml.util.IndexingObjectStore; +import org.opensaml.xml.validation.AbstractValidatingXMLObject; + +/** Concrete implementation of {@link X509CRL}. */ +public class X509CRLImpl extends AbstractValidatingXMLObject implements X509CRL { + + /** Class-level index of Base64 encoded CRL values. */ + private static final IndexingObjectStore B64_CRL_STORE = new IndexingObjectStore(); + + /** Index to a stored Base64 encoded CRL. */ + private String b64CRLIndex; + + /** + * Constructor. + * + * @param namespaceURI the namespace the element is in + * @param elementLocalName the local name of the XML element this Object represents + * @param namespacePrefix the prefix for the given namespace + */ + protected X509CRLImpl(String namespaceURI, String elementLocalName, String namespacePrefix) { + super(namespaceURI, elementLocalName, namespacePrefix); + } + + /** {@inheritDoc} */ + public String getValue() { + return B64_CRL_STORE.get(b64CRLIndex); + } + + /** {@inheritDoc} */ + public void setValue(String newValue) { + // Dump our cached DOM if the new value really is new + String currentCert = B64_CRL_STORE.get(b64CRLIndex); + String b64Cert = prepareForAssignment(currentCert, newValue); + + // This is a new value, remove the old one, add the new one + if (!DatatypeHelper.safeEquals(currentCert, b64Cert)) { + B64_CRL_STORE.remove(b64CRLIndex); + b64CRLIndex = B64_CRL_STORE.put(b64Cert); + } + } + + /** {@inheritDoc} */ + public List getOrderedChildren() { + return Collections.EMPTY_LIST; + } + + /** {@inheritDoc} */ + protected void finalize() throws Throwable { + super.finalize(); + B64_CRL_STORE.remove(b64CRLIndex); + } +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/X509CertificateBuilder.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/X509CertificateBuilder.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/X509CertificateBuilder.java 17 Aug 2012 15:17:02 -0000 1.1 @@ -0,0 +1,47 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature.impl; + +import org.opensaml.xml.AbstractXMLObjectBuilder; +import org.opensaml.xml.signature.X509Certificate; +import org.opensaml.xml.signature.XMLSignatureBuilder; +import org.opensaml.xml.util.XMLConstants; + +/** + * Builder of {@link org.opensaml.xml.signature.X509Certificate} + */ +public class X509CertificateBuilder extends AbstractXMLObjectBuilder implements XMLSignatureBuilder { + + /** + * Constructor + * + */ + public X509CertificateBuilder() { + } + + /** {@inheritDoc} */ + public X509Certificate buildObject(String namespaceURI, String localName, String namespacePrefix) { + return new X509CertificateImpl(namespaceURI, localName, namespacePrefix); + } + + /** {@inheritDoc} */ + public X509Certificate buildObject() { + return buildObject(XMLConstants.XMLSIG_NS, X509Certificate.DEFAULT_ELEMENT_LOCAL_NAME, XMLConstants.XMLSIG_PREFIX); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/X509CertificateImpl.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/X509CertificateImpl.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/X509CertificateImpl.java 17 Aug 2012 15:17:02 -0000 1.1 @@ -0,0 +1,77 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature.impl; + +import java.util.Collections; +import java.util.List; + +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.signature.X509Certificate; +import org.opensaml.xml.util.DatatypeHelper; +import org.opensaml.xml.util.IndexingObjectStore; +import org.opensaml.xml.validation.AbstractValidatingXMLObject; + +/** Concrete implementation of {@link X509Certificate}. */ +public class X509CertificateImpl extends AbstractValidatingXMLObject implements X509Certificate { + + /** Class-level index of Base64 encoded cert values. */ + private static final IndexingObjectStore B64_CERT_STORE = new IndexingObjectStore(); + + /** Index to a stored Base64 encoded cert. */ + private String b64CertIndex; + + /** + * Constructor. + * + * @param namespaceURI the namespace the element is in + * @param elementLocalName the local name of the XML element this Object represents + * @param namespacePrefix the prefix for the given namespace + */ + protected X509CertificateImpl(String namespaceURI, String elementLocalName, String namespacePrefix) { + super(namespaceURI, elementLocalName, namespacePrefix); + } + + /** {@inheritDoc} */ + public String getValue() { + return B64_CERT_STORE.get(b64CertIndex); + } + + /** {@inheritDoc} */ + public void setValue(String newValue) { + // Dump our cached DOM if the new value really is new + String currentCert = B64_CERT_STORE.get(b64CertIndex); + String b64Cert = prepareForAssignment(currentCert, newValue); + + // This is a new value, remove the old one, add the new one + if (!DatatypeHelper.safeEquals(currentCert, b64Cert)) { + B64_CERT_STORE.remove(b64CertIndex); + b64CertIndex = B64_CERT_STORE.put(b64Cert); + } + } + + /** {@inheritDoc} */ + public List getOrderedChildren() { + return Collections.EMPTY_LIST; + } + + /** {@inheritDoc} */ + protected void finalize() throws Throwable { + super.finalize(); + B64_CERT_STORE.remove(b64CertIndex); + } +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/X509DataBuilder.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/X509DataBuilder.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/X509DataBuilder.java 17 Aug 2012 15:17:01 -0000 1.1 @@ -0,0 +1,47 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature.impl; + +import org.opensaml.xml.AbstractXMLObjectBuilder; +import org.opensaml.xml.signature.X509Data; +import org.opensaml.xml.signature.XMLSignatureBuilder; +import org.opensaml.xml.util.XMLConstants; + +/** + * Builder of {@link org.opensaml.xml.signature.X509Data} + */ +public class X509DataBuilder extends AbstractXMLObjectBuilder implements XMLSignatureBuilder { + + /** + * Constructor + * + */ + public X509DataBuilder() { + } + + /** {@inheritDoc} */ + public X509Data buildObject(String namespaceURI, String localName, String namespacePrefix) { + return new X509DataImpl(namespaceURI, localName, namespacePrefix); + } + + /** {@inheritDoc} */ + public X509Data buildObject() { + return buildObject(XMLConstants.XMLSIG_NS, X509Data.DEFAULT_ELEMENT_LOCAL_NAME, XMLConstants.XMLSIG_PREFIX); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/X509DataImpl.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/X509DataImpl.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/X509DataImpl.java 17 Aug 2012 15:17:00 -0000 1.1 @@ -0,0 +1,102 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature.impl; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import javax.xml.namespace.QName; + +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.signature.X509CRL; +import org.opensaml.xml.signature.X509Certificate; +import org.opensaml.xml.signature.X509Data; +import org.opensaml.xml.signature.X509IssuerSerial; +import org.opensaml.xml.signature.X509SKI; +import org.opensaml.xml.signature.X509SubjectName; +import org.opensaml.xml.util.IndexedXMLObjectChildrenList; +import org.opensaml.xml.validation.AbstractValidatingXMLObject; + +/** Concrete implementation of {@link X509Data}. */ +public class X509DataImpl extends AbstractValidatingXMLObject implements X509Data { + + /** The list of XMLObject child elements. */ + private final IndexedXMLObjectChildrenList indexedChildren; + + /** + * Constructor. + * + * @param namespaceURI the namespace the element is in + * @param elementLocalName the local name of the XML element this Object represents + * @param namespacePrefix the prefix for the given namespace + */ + protected X509DataImpl(String namespaceURI, String elementLocalName, String namespacePrefix) { + super(namespaceURI, elementLocalName, namespacePrefix); + indexedChildren = new IndexedXMLObjectChildrenList(this); + } + + /** {@inheritDoc} */ + public List getXMLObjects() { + return (List) this.indexedChildren; + } + + /** {@inheritDoc} */ + public List getXMLObjects(QName typeOrName) { + return (List) this.indexedChildren.subList(typeOrName); + } + + /** {@inheritDoc} */ + public List getX509IssuerSerials() { + return (List) this.indexedChildren.subList(X509IssuerSerial.DEFAULT_ELEMENT_NAME); + } + + /** {@inheritDoc} */ + public List getX509SKIs() { + return (List) this.indexedChildren.subList(X509SKI.DEFAULT_ELEMENT_NAME); + } + + /** {@inheritDoc} */ + public List getX509SubjectNames() { + return (List) this.indexedChildren.subList(X509SubjectName.DEFAULT_ELEMENT_NAME); + } + + /** {@inheritDoc} */ + public List getX509Certificates() { + return (List) this.indexedChildren.subList(X509Certificate.DEFAULT_ELEMENT_NAME); + } + + /** {@inheritDoc} */ + public List getX509CRLs() { + return (List) this.indexedChildren.subList(X509CRL.DEFAULT_ELEMENT_NAME); + } + + /** {@inheritDoc} */ + public List getOrderedChildren() { + ArrayList children = new ArrayList(); + + children.addAll((List) indexedChildren); + + if (children.size() == 0) { + return null; + } + + return Collections.unmodifiableList(children); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/X509DataMarshaller.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/X509DataMarshaller.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/X509DataMarshaller.java 17 Aug 2012 15:17:00 -0000 1.1 @@ -0,0 +1,25 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature.impl; + +/** + * A thread-safe Marshaller for {@link org.opensaml.xml.signature.X509Data} objects. + */ +public class X509DataMarshaller extends AbstractXMLSignatureMarshaller { + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/X509DataUnmarshaller.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/X509DataUnmarshaller.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/X509DataUnmarshaller.java 17 Aug 2012 15:17:01 -0000 1.1 @@ -0,0 +1,40 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature.impl; + +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.io.UnmarshallingException; +import org.opensaml.xml.signature.X509Data; + +/** + * A thread-safe Unmarshaller for {@link org.opensaml.xml.signature.X509Data} objects. + */ +public class X509DataUnmarshaller extends AbstractXMLSignatureUnmarshaller { + + /** {@inheritDoc} */ + protected void processChildElement(XMLObject parentXMLObject, XMLObject childXMLObject) + throws UnmarshallingException { + X509Data x509Data = (X509Data) parentXMLObject; + + // X509Data contains a range of specific types, but also + // support , with an unbounded choice over all (no ordering) + // so no need to distinguish. + x509Data.getXMLObjects().add(childXMLObject); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/X509IssuerNameBuilder.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/X509IssuerNameBuilder.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/X509IssuerNameBuilder.java 17 Aug 2012 15:17:03 -0000 1.1 @@ -0,0 +1,47 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature.impl; + +import org.opensaml.xml.AbstractXMLObjectBuilder; +import org.opensaml.xml.signature.X509IssuerName; +import org.opensaml.xml.signature.XMLSignatureBuilder; +import org.opensaml.xml.util.XMLConstants; + +/** + * Builder of {@link org.opensaml.xml.signature.X509IssuerName} + */ +public class X509IssuerNameBuilder extends AbstractXMLObjectBuilder implements XMLSignatureBuilder { + + /** + * Constructor + * + */ + public X509IssuerNameBuilder() { + } + + /** {@inheritDoc} */ + public X509IssuerName buildObject(String namespaceURI, String localName, String namespacePrefix) { + return new X509IssuerNameImpl(namespaceURI, localName, namespacePrefix); + } + + /** {@inheritDoc} */ + public X509IssuerName buildObject() { + return buildObject(XMLConstants.XMLSIG_NS, X509IssuerName.DEFAULT_ELEMENT_LOCAL_NAME, XMLConstants.XMLSIG_PREFIX); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/X509IssuerNameImpl.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/X509IssuerNameImpl.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/X509IssuerNameImpl.java 17 Aug 2012 15:17:02 -0000 1.1 @@ -0,0 +1,39 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature.impl; + +import org.opensaml.xml.schema.impl.XSStringImpl; +import org.opensaml.xml.signature.X509IssuerName; + +/** + * Concrete implementation of {@link org.opensaml.xml.signature.X509IssuerName} + */ +public class X509IssuerNameImpl extends XSStringImpl implements X509IssuerName { + + /** + * Constructor + * + * @param namespaceURI + * @param elementLocalName + * @param namespacePrefix + */ + protected X509IssuerNameImpl(String namespaceURI, String elementLocalName, String namespacePrefix) { + super(namespaceURI, elementLocalName, namespacePrefix); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/X509IssuerSerialBuilder.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/X509IssuerSerialBuilder.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/X509IssuerSerialBuilder.java 17 Aug 2012 15:17:00 -0000 1.1 @@ -0,0 +1,47 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature.impl; + +import org.opensaml.xml.AbstractXMLObjectBuilder; +import org.opensaml.xml.signature.X509IssuerSerial; +import org.opensaml.xml.signature.XMLSignatureBuilder; +import org.opensaml.xml.util.XMLConstants; + +/** + * Builder of {@link org.opensaml.xml.signature.X509IssuerSerial} + */ +public class X509IssuerSerialBuilder extends AbstractXMLObjectBuilder implements XMLSignatureBuilder { + + /** + * Constructor + * + */ + public X509IssuerSerialBuilder() { + } + + /** {@inheritDoc} */ + public X509IssuerSerial buildObject(String namespaceURI, String localName, String namespacePrefix) { + return new X509IssuerSerialImpl(namespaceURI, localName, namespacePrefix); + } + + /** {@inheritDoc} */ + public X509IssuerSerial buildObject() { + return buildObject(XMLConstants.XMLSIG_NS, X509IssuerSerial.DEFAULT_ELEMENT_LOCAL_NAME, XMLConstants.XMLSIG_PREFIX); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/X509IssuerSerialImpl.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/X509IssuerSerialImpl.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/X509IssuerSerialImpl.java 17 Aug 2012 15:17:03 -0000 1.1 @@ -0,0 +1,90 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature.impl; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.signature.X509IssuerName; +import org.opensaml.xml.signature.X509IssuerSerial; +import org.opensaml.xml.signature.X509SerialNumber; +import org.opensaml.xml.validation.AbstractValidatingXMLObject; + +/** + * Concrete implementation of {@link org.opensaml.xml.signature.X509IssuerSerial} + */ +public class X509IssuerSerialImpl extends AbstractValidatingXMLObject implements X509IssuerSerial { + + /** X509IssuerName child element */ + private X509IssuerName issuerName; + + /** X509SerialNumber child element */ + private X509SerialNumber serialNumber; + + /** + * Constructor + * + * @param namespaceURI + * @param elementLocalName + * @param namespacePrefix + */ + protected X509IssuerSerialImpl(String namespaceURI, String elementLocalName, String namespacePrefix) { + super(namespaceURI, elementLocalName, namespacePrefix); + } + + /** {@inheritDoc} */ + public X509IssuerName getX509IssuerName() { + return this.issuerName; + } + + /** {@inheritDoc} */ + public void setX509IssuerName(X509IssuerName newX509IssuerName) { + this.issuerName = prepareForAssignment(this.issuerName, newX509IssuerName); + } + + /** {@inheritDoc} */ + public X509SerialNumber getX509SerialNumber() { + return this.serialNumber; + } + + /** {@inheritDoc} */ + public void setX509SerialNumber(X509SerialNumber newX509SerialNumber) { + this.serialNumber = prepareForAssignment(this.serialNumber, newX509SerialNumber); + } + + /** {@inheritDoc} */ + public List getOrderedChildren() { + ArrayList children = new ArrayList(); + + if (issuerName != null) { + children.add(issuerName); + } + if (serialNumber != null) { + children.add(serialNumber); + } + + if (children.size() == 0) { + return null; + } + + return Collections.unmodifiableList(children); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/X509IssuerSerialMarshaller.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/X509IssuerSerialMarshaller.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/X509IssuerSerialMarshaller.java 17 Aug 2012 15:17:00 -0000 1.1 @@ -0,0 +1,25 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature.impl; + +/** + * A thread-safe Marshaller for {@link org.opensaml.xml.signature.X509IssuerSerial} objects. + */ +public class X509IssuerSerialMarshaller extends AbstractXMLSignatureMarshaller { + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/X509IssuerSerialUnmarshaller.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/X509IssuerSerialUnmarshaller.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/X509IssuerSerialUnmarshaller.java 17 Aug 2012 15:17:01 -0000 1.1 @@ -0,0 +1,45 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature.impl; + +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.io.UnmarshallingException; +import org.opensaml.xml.signature.X509IssuerName; +import org.opensaml.xml.signature.X509IssuerSerial; +import org.opensaml.xml.signature.X509SerialNumber; + +/** + * A thread-safe Unmarshaller for {@link org.opensaml.xml.signature.X509IssuerSerial} objects. + */ +public class X509IssuerSerialUnmarshaller extends AbstractXMLSignatureUnmarshaller { + + /** {@inheritDoc} */ + protected void processChildElement(XMLObject parentXMLObject, XMLObject childXMLObject) + throws UnmarshallingException { + X509IssuerSerial keyValue = (X509IssuerSerial) parentXMLObject; + + if (childXMLObject instanceof X509IssuerName) { + keyValue.setX509IssuerName((X509IssuerName) childXMLObject); + } else if (childXMLObject instanceof X509SerialNumber) { + keyValue.setX509SerialNumber((X509SerialNumber) childXMLObject); + } else { + super.processChildElement(parentXMLObject, childXMLObject); + } + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/X509SKIBuilder.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/X509SKIBuilder.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/X509SKIBuilder.java 17 Aug 2012 15:17:00 -0000 1.1 @@ -0,0 +1,47 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature.impl; + +import org.opensaml.xml.AbstractXMLObjectBuilder; +import org.opensaml.xml.signature.X509SKI; +import org.opensaml.xml.signature.XMLSignatureBuilder; +import org.opensaml.xml.util.XMLConstants; + +/** + * Builder of {@link org.opensaml.xml.signature.X509SKI} + */ +public class X509SKIBuilder extends AbstractXMLObjectBuilder implements XMLSignatureBuilder { + + /** + * Constructor + * + */ + public X509SKIBuilder() { + } + + /** {@inheritDoc} */ + public X509SKI buildObject(String namespaceURI, String localName, String namespacePrefix) { + return new X509SKIImpl(namespaceURI, localName, namespacePrefix); + } + + /** {@inheritDoc} */ + public X509SKI buildObject() { + return buildObject(XMLConstants.XMLSIG_NS, X509SKI.DEFAULT_ELEMENT_LOCAL_NAME, XMLConstants.XMLSIG_PREFIX); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/X509SKIImpl.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/X509SKIImpl.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/X509SKIImpl.java 17 Aug 2012 15:17:01 -0000 1.1 @@ -0,0 +1,39 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature.impl; + +import org.opensaml.xml.schema.impl.XSBase64BinaryImpl; +import org.opensaml.xml.signature.X509SKI; + +/** + * Concrete implementation of {@link org.opensaml.xml.signature.X509SKI} + */ +public class X509SKIImpl extends XSBase64BinaryImpl implements X509SKI { + + /** + * Constructor + * + * @param namespaceURI + * @param elementLocalName + * @param namespacePrefix + */ + protected X509SKIImpl(String namespaceURI, String elementLocalName, String namespacePrefix) { + super(namespaceURI, elementLocalName, namespacePrefix); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/X509SerialNumberBuilder.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/X509SerialNumberBuilder.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/X509SerialNumberBuilder.java 17 Aug 2012 15:17:03 -0000 1.1 @@ -0,0 +1,49 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature.impl; + +import org.opensaml.xml.AbstractXMLObjectBuilder; +import org.opensaml.xml.signature.X509SerialNumber; +import org.opensaml.xml.signature.XMLSignatureBuilder; +import org.opensaml.xml.util.XMLConstants; + +/** + * Builder of {@link org.opensaml.xml.signature.X509SerialNumber}. + */ +public class X509SerialNumberBuilder extends AbstractXMLObjectBuilder + implements XMLSignatureBuilder { + + /** + * Constructor. + * + */ + public X509SerialNumberBuilder() { + } + + /** {@inheritDoc} */ + public X509SerialNumber buildObject(String namespaceURI, String localName, String namespacePrefix) { + return new X509SerialNumberImpl(namespaceURI, localName, namespacePrefix); + } + + /** {@inheritDoc} */ + public X509SerialNumber buildObject() { + return buildObject(XMLConstants.XMLSIG_NS, X509SerialNumber.DEFAULT_ELEMENT_LOCAL_NAME, + XMLConstants.XMLSIG_PREFIX); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/X509SerialNumberImpl.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/X509SerialNumberImpl.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/X509SerialNumberImpl.java 17 Aug 2012 15:17:01 -0000 1.1 @@ -0,0 +1,64 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature.impl; + +import java.math.BigInteger; +import java.util.List; + +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.signature.X509SerialNumber; +import org.opensaml.xml.validation.AbstractValidatingXMLObject; + +/** + * Concrete implementation of {@link org.opensaml.xml.signature.X509SerialNumber}. + */ +public class X509SerialNumberImpl extends AbstractValidatingXMLObject implements X509SerialNumber { + + /** The serial number value. */ + private BigInteger value; + + /** + * Constructor. + * + * @param namespaceURI the namespace the element is in + * @param elementLocalName the local name of the XML element this Object represents + * @param namespacePrefix the prefix for the given namespace + */ + protected X509SerialNumberImpl(String namespaceURI, String elementLocalName, String namespacePrefix) { + super(namespaceURI, elementLocalName, namespacePrefix); + } + + /** {@inheritDoc} */ + public BigInteger getValue() { + return value; + } + + /** {@inheritDoc} */ + public void setValue(BigInteger newValue) { + value = prepareForAssignment(value, newValue); + } + + /** + * {@inheritDoc} + */ + public List getOrderedChildren() { + // no children + return null; + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/X509SerialNumberMarshaller.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/X509SerialNumberMarshaller.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/X509SerialNumberMarshaller.java 17 Aug 2012 15:17:01 -0000 1.1 @@ -0,0 +1,45 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature.impl; + +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.io.AbstractXMLObjectMarshaller; +import org.opensaml.xml.io.MarshallingException; +import org.opensaml.xml.signature.X509SerialNumber; +import org.opensaml.xml.util.XMLHelper; +import org.w3c.dom.Element; + +/** + * Thread-safe marshaller of {@link X509SerialNumber} objects. + */ +public class X509SerialNumberMarshaller extends AbstractXMLObjectMarshaller { + + /** {@inheritDoc} */ + protected void marshallAttributes(XMLObject xmlObject, Element domElement) throws MarshallingException { + // no attributes + } + + /** {@inheritDoc} */ + protected void marshallElementContent(XMLObject xmlObject, Element domElement) throws MarshallingException { + X509SerialNumber x509SerialNumber = (X509SerialNumber) xmlObject; + + if (x509SerialNumber.getValue() != null) { + XMLHelper.appendTextContent(domElement, x509SerialNumber.getValue().toString()); + } + } +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/X509SerialNumberUnmarshaller.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/X509SerialNumberUnmarshaller.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/X509SerialNumberUnmarshaller.java 17 Aug 2012 15:17:04 -0000 1.1 @@ -0,0 +1,53 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature.impl; + +import java.math.BigInteger; + +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.io.AbstractXMLObjectUnmarshaller; +import org.opensaml.xml.io.UnmarshallingException; +import org.opensaml.xml.signature.X509SerialNumber; +import org.opensaml.xml.util.DatatypeHelper; +import org.w3c.dom.Attr; + +/** + * Thread-safe unmarshaller for {@link X509SerialNumber} objects. + */ +public class X509SerialNumberUnmarshaller extends AbstractXMLObjectUnmarshaller { + + /** {@inheritDoc} */ + protected void processChildElement(XMLObject parentXMLObject, XMLObject childXMLObject) + throws UnmarshallingException { + // no children + } + + /** {@inheritDoc} */ + protected void processAttribute(XMLObject xmlObject, Attr attribute) throws UnmarshallingException { + //no attributes + } + + /** {@inheritDoc} */ + protected void processElementContent(XMLObject xmlObject, String elementContent) { + X509SerialNumber x509SerialNumber = (X509SerialNumber) xmlObject; + + if(! DatatypeHelper.isEmpty(elementContent)){ + x509SerialNumber.setValue( new BigInteger(elementContent) ); + } + } +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/X509SubjectNameBuilder.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/X509SubjectNameBuilder.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/X509SubjectNameBuilder.java 17 Aug 2012 15:17:03 -0000 1.1 @@ -0,0 +1,47 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature.impl; + +import org.opensaml.xml.AbstractXMLObjectBuilder; +import org.opensaml.xml.signature.X509SubjectName; +import org.opensaml.xml.signature.XMLSignatureBuilder; +import org.opensaml.xml.util.XMLConstants; + +/** + * Builder of {@link org.opensaml.xml.signature.X509SubjectName} + */ +public class X509SubjectNameBuilder extends AbstractXMLObjectBuilder implements XMLSignatureBuilder { + + /** + * Constructor + * + */ + public X509SubjectNameBuilder() { + } + + /** {@inheritDoc} */ + public X509SubjectName buildObject(String namespaceURI, String localName, String namespacePrefix) { + return new X509SubjectNameImpl(namespaceURI, localName, namespacePrefix); + } + + /** {@inheritDoc} */ + public X509SubjectName buildObject() { + return buildObject(XMLConstants.XMLSIG_NS, X509SubjectName.DEFAULT_ELEMENT_LOCAL_NAME, XMLConstants.XMLSIG_PREFIX); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/X509SubjectNameImpl.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/X509SubjectNameImpl.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/X509SubjectNameImpl.java 17 Aug 2012 15:17:03 -0000 1.1 @@ -0,0 +1,39 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature.impl; + +import org.opensaml.xml.schema.impl.XSStringImpl; +import org.opensaml.xml.signature.X509SubjectName; + +/** + * Concrete implementation of {@link org.opensaml.xml.signature.X509SubjectName} + */ +public class X509SubjectNameImpl extends XSStringImpl implements X509SubjectName { + + /** + * Constructor + * + * @param namespaceURI + * @param elementLocalName + * @param namespacePrefix + */ + protected X509SubjectNameImpl(String namespaceURI, String elementLocalName, String namespacePrefix) { + super(namespaceURI, elementLocalName, namespacePrefix); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/XPathBuilder.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/XPathBuilder.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/XPathBuilder.java 17 Aug 2012 15:17:02 -0000 1.1 @@ -0,0 +1,47 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature.impl; + +import org.opensaml.xml.AbstractXMLObjectBuilder; +import org.opensaml.xml.signature.XMLSignatureBuilder; +import org.opensaml.xml.signature.XPath; +import org.opensaml.xml.util.XMLConstants; + +/** + * Builder of {@link org.opensaml.xml.signature.XPath} + */ +public class XPathBuilder extends AbstractXMLObjectBuilder implements XMLSignatureBuilder { + + /** + * Constructor + * + */ + public XPathBuilder() { + } + + /** {@inheritDoc} */ + public XPath buildObject(String namespaceURI, String localName, String namespacePrefix) { + return new XPathImpl(namespaceURI, localName, namespacePrefix); + } + + /** {@inheritDoc} */ + public XPath buildObject() { + return buildObject(XMLConstants.XMLSIG_NS, XPath.DEFAULT_ELEMENT_LOCAL_NAME, XMLConstants.XMLSIG_PREFIX); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/XPathImpl.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/XPathImpl.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/XPathImpl.java 17 Aug 2012 15:17:03 -0000 1.1 @@ -0,0 +1,39 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature.impl; + +import org.opensaml.xml.schema.impl.XSStringImpl; +import org.opensaml.xml.signature.XPath; + +/** + * Concrete implementation of {@link org.opensaml.xml.signature.XPath} + */ +public class XPathImpl extends XSStringImpl implements XPath { + + /** + * Constructor + * + * @param namespaceURI + * @param elementLocalName + * @param namespacePrefix + */ + protected XPathImpl(String namespaceURI, String elementLocalName, String namespacePrefix) { + super(namespaceURI, elementLocalName, namespacePrefix); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/YBuilder.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/YBuilder.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/YBuilder.java 17 Aug 2012 15:17:04 -0000 1.1 @@ -0,0 +1,47 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature.impl; + +import org.opensaml.xml.AbstractXMLObjectBuilder; +import org.opensaml.xml.signature.Y; +import org.opensaml.xml.signature.XMLSignatureBuilder; +import org.opensaml.xml.util.XMLConstants; + +/** + * Builder of {@link org.opensaml.xml.signature.Y} + */ +public class YBuilder extends AbstractXMLObjectBuilder implements XMLSignatureBuilder { + + /** + * Constructor + * + */ + public YBuilder() { + } + + /** {@inheritDoc} */ + public Y buildObject(String namespaceURI, String localName, String namespacePrefix) { + return new YImpl(namespaceURI, localName, namespacePrefix); + } + + /** {@inheritDoc} */ + public Y buildObject() { + return buildObject(XMLConstants.XMLSIG_NS, Y.DEFAULT_ELEMENT_LOCAL_NAME, XMLConstants.XMLSIG_PREFIX); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/YImpl.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/YImpl.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/YImpl.java 17 Aug 2012 15:17:02 -0000 1.1 @@ -0,0 +1,38 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature.impl; + +import org.opensaml.xml.signature.Y; + +/** + * Concrete implementation of {@link org.opensaml.xml.signature.Y} + */ +public class YImpl extends CryptoBinaryImpl implements Y { + + /** + * Constructor + * + * @param namespaceURI + * @param elementLocalName + * @param namespacePrefix + */ + protected YImpl(String namespaceURI, String elementLocalName, String namespacePrefix) { + super(namespaceURI, elementLocalName, namespacePrefix); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/package.html =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/package.html,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/impl/package.html 17 Aug 2012 15:17:00 -0000 1.1 @@ -0,0 +1,5 @@ + + +Implementations of the interfaces for XMLObjects that represent XML signature types. + + \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/validator/CryptoBinarySchemaValidator.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/validator/CryptoBinarySchemaValidator.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/validator/CryptoBinarySchemaValidator.java 17 Aug 2012 15:17:04 -0000 1.1 @@ -0,0 +1,37 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature.validator; + +import org.opensaml.xml.schema.validator.XSBase64BinarySchemaValidator; +import org.opensaml.xml.signature.CryptoBinary; + +/** + * Checks {@link org.opensaml.xml.signature.CryptoBinary} for Schema compliance. + */ +public class CryptoBinarySchemaValidator extends XSBase64BinarySchemaValidator { + + /** + * Constructor. + * + */ + public CryptoBinarySchemaValidator() { + // Don't allow empty content + super(false); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/validator/DSAKeyValueSchemaValidator.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/validator/DSAKeyValueSchemaValidator.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/validator/DSAKeyValueSchemaValidator.java 17 Aug 2012 15:17:04 -0000 1.1 @@ -0,0 +1,58 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature.validator; + +import org.opensaml.xml.signature.DSAKeyValue; +import org.opensaml.xml.validation.ValidationException; +import org.opensaml.xml.validation.Validator; + +/** + * Checks {@link org.opensaml.xml.signature.DSAKeyValue} for Schema compliance. + */ +public class DSAKeyValueSchemaValidator implements Validator { + + /** {@inheritDoc} */ + public void validate(DSAKeyValue xmlObject) throws ValidationException { + validateChildrenPresence(xmlObject); + } + + /** + * Validate that all children are present. + * + * @param xmlObject the object to validate + * @throws ValidationException thrown if the object is invalid + */ + protected void validateChildrenPresence(DSAKeyValue xmlObject) throws ValidationException { + if (xmlObject.getY() == null) { + throw new ValidationException("DSAKeyValue did not contain a required Y value"); + } + + if (xmlObject.getP() != null && xmlObject.getQ() == null) { + throw new ValidationException("RSAKeyValue did contained a P value without a Q value"); + } else if (xmlObject.getQ() != null && xmlObject.getP() == null) { + throw new ValidationException("RSAKeyValue did contained a Q value without a P value"); + } + + if (xmlObject.getPgenCounter() != null && xmlObject.getSeed() == null) { + throw new ValidationException("RSAKeyValue did contained a PgenCounter value without a Seed value"); + } else if (xmlObject.getSeed() != null && xmlObject.getPgenCounter() == null) { + throw new ValidationException("RSAKeyValue did contained a Seed value without a PgenCounter value"); + } + + } +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/validator/KeyInfoTypeSchemaValidator.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/validator/KeyInfoTypeSchemaValidator.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/validator/KeyInfoTypeSchemaValidator.java 17 Aug 2012 15:17:04 -0000 1.1 @@ -0,0 +1,103 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature.validator; + +import java.util.HashSet; +import java.util.Set; + +import javax.xml.namespace.QName; + +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.signature.KeyInfoType; +import org.opensaml.xml.signature.KeyName; +import org.opensaml.xml.signature.KeyValue; +import org.opensaml.xml.signature.MgmtData; +import org.opensaml.xml.signature.PGPData; +import org.opensaml.xml.signature.RetrievalMethod; +import org.opensaml.xml.signature.SPKIData; +import org.opensaml.xml.signature.X509Data; +import org.opensaml.xml.util.XMLConstants; +import org.opensaml.xml.validation.ValidationException; +import org.opensaml.xml.validation.Validator; + +/** + * Checks {@link org.opensaml.xml.signature.KeyInfoType} for Schema compliance. + */ +public class KeyInfoTypeSchemaValidator implements Validator { + + /** QNames corresponding to the valid KeyInfo children. */ + private static final Set VALID_DS_CHILD_NAMES; + + /** {@inheritDoc} */ + public void validate(KeyInfoType xmlObject) throws ValidationException { + validateChildrenPresence(xmlObject); + validateChildrenNamespaces(xmlObject); + } + + /** + * Get the QNames corresponding to the valid KeyInfo children + * defined in the XML Signature namespace. + * + * @return list of valid child QNames + */ + protected static Set getValidDSChildNames() { + return VALID_DS_CHILD_NAMES; + } + + /** + * Validate that at least child is present. + * + * @param xmlObject the object to validate + * @throws ValidationException thrown if the object is invalid + */ + protected void validateChildrenPresence(KeyInfoType xmlObject) throws ValidationException { + if (xmlObject.getXMLObjects().isEmpty()) { + throw new ValidationException("No children were present in the KeyInfoType object"); + } + } + + /** + * Validate that all children are either ones defined within the XML Signature schema, + * or are from another namespace. + * + * @param xmlObject the object to validate + * @throws ValidationException thrown if the object is invalid + */ + protected void validateChildrenNamespaces(KeyInfoType xmlObject) throws ValidationException { + // Validate that any children are either the ones from the dsig schema, + // or are from another namespace. + for (XMLObject child : xmlObject.getXMLObjects()) { + QName childName = child.getElementQName(); + if (! getValidDSChildNames().contains(childName) + && XMLConstants.XMLSIG_NS.equals(childName.getNamespaceURI())) { + throw new ValidationException("KeyInfoType contains an illegal child extension element: " + childName); + } + } + } + + static { + VALID_DS_CHILD_NAMES = new HashSet(10); + VALID_DS_CHILD_NAMES.add(KeyName.DEFAULT_ELEMENT_NAME); + VALID_DS_CHILD_NAMES.add(KeyValue.DEFAULT_ELEMENT_NAME); + VALID_DS_CHILD_NAMES.add(RetrievalMethod.DEFAULT_ELEMENT_NAME); + VALID_DS_CHILD_NAMES.add(X509Data.DEFAULT_ELEMENT_NAME); + VALID_DS_CHILD_NAMES.add(PGPData.DEFAULT_ELEMENT_NAME); + VALID_DS_CHILD_NAMES.add(SPKIData.DEFAULT_ELEMENT_NAME); + VALID_DS_CHILD_NAMES.add(MgmtData.DEFAULT_ELEMENT_NAME); + } +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/validator/KeyValueSchemaValidator.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/validator/KeyValueSchemaValidator.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/validator/KeyValueSchemaValidator.java 17 Aug 2012 15:17:04 -0000 1.1 @@ -0,0 +1,75 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature.validator; + +import java.util.List; + +import javax.xml.namespace.QName; + +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.signature.KeyValue; +import org.opensaml.xml.util.XMLConstants; +import org.opensaml.xml.validation.ValidationException; +import org.opensaml.xml.validation.Validator; + +/** + * Checks {@link org.opensaml.xml.signature.KeyValue} for Schema compliance. + */ +public class KeyValueSchemaValidator implements Validator { + + /** {@inheritDoc} */ + public void validate(KeyValue xmlObject) throws ValidationException { + validateChildrenPresence(xmlObject); + validateExtensionChildNamespace(xmlObject); + } + + /** + * Validate that exactly one child is present. + * + * @param xmlObject the object to validate + * @throws ValidationException thrown if the object is invalid + */ + protected void validateChildrenPresence(KeyValue xmlObject) throws ValidationException { + List children = xmlObject.getOrderedChildren(); + if (children == null || children.isEmpty()) { + throw new ValidationException("No children were present in the KeyValue object"); + } + if (children.size() > 1) { + throw new ValidationException("Invalid number of children were present in the KeyValue object"); + } + } + + /** + * Validate that the extension child, if present, is from another namespace. + * + * @param xmlObject the object to validate + * @throws ValidationException thrown if the object is invalid + */ + protected void validateExtensionChildNamespace(KeyValue xmlObject) throws ValidationException { + // Validate that the unknown child is not from the dsig namespace + // or are from another namespace. + XMLObject unknownChild = xmlObject.getUnknownXMLObject(); + if (unknownChild == null) { + return; + } + QName childName = unknownChild.getElementQName(); + if (XMLConstants.XMLSIG_NS.equals(childName.getNamespaceURI())) { + throw new ValidationException("KeyValue contains an illegal child extension element: " + childName); + } + } +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/validator/PGPDataSchemaValidator.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/validator/PGPDataSchemaValidator.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/validator/PGPDataSchemaValidator.java 17 Aug 2012 15:17:04 -0000 1.1 @@ -0,0 +1,92 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature.validator; + +import java.util.HashSet; +import java.util.Set; + +import javax.xml.namespace.QName; + +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.signature.PGPData; +import org.opensaml.xml.signature.PGPKeyID; +import org.opensaml.xml.signature.PGPKeyPacket; +import org.opensaml.xml.util.XMLConstants; +import org.opensaml.xml.validation.ValidationException; +import org.opensaml.xml.validation.Validator; + +/** + * Checks {@link org.opensaml.xml.signature.PGPData} for Schema compliance. + */ +public class PGPDataSchemaValidator implements Validator { + + /** QNames corresponding to the valid children. */ + private static final Set VALID_DS_CHILD_NAMES; + + /** {@inheritDoc} */ + public void validate(PGPData xmlObject) throws ValidationException { + validateChildrenPresence(xmlObject); + validateChildrenNamespaces(xmlObject); + } + + /** + * Get the QNames corresponding to the valid children + * defined in the XML Signature namespace. + * + * @return list of valid child QNames + */ + protected static Set getValidDSChildNames() { + return VALID_DS_CHILD_NAMES; + } + + /** + * Validate that at least one mandatory child is present. + * + * @param xmlObject the object to validate + * @throws ValidationException thrown if the object is invalid + */ + protected void validateChildrenPresence(PGPData xmlObject) throws ValidationException { + if (xmlObject.getPGPKeyID() == null && xmlObject.getPGPKeyPacket() == null) { + throw new ValidationException("PGPData must contain at least one of PGPKeyID or PGPKeyPacket"); + } + } + + /** + * Validate that all children are either ones defined within the XML Signature schema, + * or are from another namespace. + * + * @param xmlObject the object to validate + * @throws ValidationException thrown if the object is invalid + */ + protected void validateChildrenNamespaces(PGPData xmlObject) throws ValidationException { + // Validate that any unknown children are from another namespace. + for (XMLObject child : xmlObject.getUnknownXMLObjects()) { + QName childName = child.getElementQName(); + if (! getValidDSChildNames().contains(childName) + && XMLConstants.XMLSIG_NS.equals(childName.getNamespaceURI())) { + throw new ValidationException("PGPData contains an illegal child extension element: " + childName); + } + } + } + + static { + VALID_DS_CHILD_NAMES = new HashSet(5); + VALID_DS_CHILD_NAMES.add(PGPKeyID.DEFAULT_ELEMENT_NAME); + VALID_DS_CHILD_NAMES.add(PGPKeyPacket.DEFAULT_ELEMENT_NAME); + } +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/validator/RSAKeyValueSchemaValidator.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/validator/RSAKeyValueSchemaValidator.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/validator/RSAKeyValueSchemaValidator.java 17 Aug 2012 15:17:04 -0000 1.1 @@ -0,0 +1,48 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature.validator; + +import org.opensaml.xml.signature.RSAKeyValue; +import org.opensaml.xml.validation.ValidationException; +import org.opensaml.xml.validation.Validator; + +/** + * Checks {@link org.opensaml.xml.signature.RSAKeyValue} for Schema compliance. + */ +public class RSAKeyValueSchemaValidator implements Validator { + + /** {@inheritDoc} */ + public void validate(RSAKeyValue xmlObject) throws ValidationException { + validateChildrenPresence(xmlObject); + } + + /** + * Validate that all children are present. + * + * @param xmlObject the object to validate + * @throws ValidationException thrown if the object is invalid + */ + protected void validateChildrenPresence(RSAKeyValue xmlObject) throws ValidationException { + if (xmlObject.getModulus() == null) { + throw new ValidationException("RSAKeyValue did not contain a required Modulus value"); + } + if (xmlObject.getExponent() == null) { + throw new ValidationException("RSAKeyValue did not contain a required Exponent value"); + } + } +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/validator/RetrievalMethodSchemaValidator.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/validator/RetrievalMethodSchemaValidator.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/validator/RetrievalMethodSchemaValidator.java 17 Aug 2012 15:17:04 -0000 1.1 @@ -0,0 +1,47 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature.validator; + +import org.opensaml.xml.signature.RetrievalMethod; +import org.opensaml.xml.util.DatatypeHelper; +import org.opensaml.xml.validation.ValidationException; +import org.opensaml.xml.validation.Validator; + +/** + * Checks {@link org.opensaml.xml.signature.RetrievalMethod} for Schema compliance. + */ +public class RetrievalMethodSchemaValidator implements Validator { + + /** {@inheritDoc} */ + public void validate(RetrievalMethod xmlObject) throws ValidationException { + validateURI(xmlObject); + } + + /** + * Validate the URI. + * + * @param xmlObject the object to validate + * @throws ValidationException thrown if the object is invalid + */ + protected void validateURI(RetrievalMethod xmlObject) throws ValidationException { + if (DatatypeHelper.isEmpty(xmlObject.getURI())) { + throw new ValidationException("RetrievalMethod URI was empty"); + } + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/validator/SPKIDataSchemaValidator.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/validator/SPKIDataSchemaValidator.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/validator/SPKIDataSchemaValidator.java 17 Aug 2012 15:17:04 -0000 1.1 @@ -0,0 +1,71 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature.validator; + +import javax.xml.namespace.QName; + +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.signature.SPKIData; +import org.opensaml.xml.signature.SPKISexp; +import org.opensaml.xml.util.XMLConstants; +import org.opensaml.xml.validation.ValidationException; +import org.opensaml.xml.validation.Validator; + +/** + * Checks {@link org.opensaml.xml.signature.SPKIData} for Schema compliance. + */ +public class SPKIDataSchemaValidator implements Validator { + + /** {@inheritDoc} */ + public void validate(SPKIData xmlObject) throws ValidationException { + validateChildrenPresence(xmlObject); + validateChildrenNamespaces(xmlObject); + } + + /** + * Validate that at least SPKISexp child is present. + * + * @param xmlObject the object to validate + * @throws ValidationException thrown if the object is invalid + */ + protected void validateChildrenPresence(SPKIData xmlObject) throws ValidationException { + if (xmlObject.getSPKISexps().isEmpty()) { + throw new ValidationException("SPKIData does not contain at least one SPKISexp child"); + } + } + + /** + * Validate that all children are either ones defined within the XML Signature schema, + * or are from another namespace. + * + * @param xmlObject the object to validate + * @throws ValidationException thrown if the object is invalid + */ + protected void validateChildrenNamespaces(SPKIData xmlObject) throws ValidationException { + // Validate that any children are either the ones from the dsig schema, + // or are from another namespace. + for (XMLObject child : xmlObject.getXMLObjects()) { + QName childName = child.getElementQName(); + if (! SPKISexp.DEFAULT_ELEMENT_NAME.equals(childName) + && XMLConstants.XMLSIG_NS.equals(childName.getNamespaceURI())) { + throw new ValidationException("PGPData contains an illegal child extension element: " + childName); + } + } + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/validator/SignatureSchemaValidator.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/validator/SignatureSchemaValidator.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/validator/SignatureSchemaValidator.java 17 Aug 2012 15:17:04 -0000 1.1 @@ -0,0 +1,60 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature.validator; + +import org.opensaml.xml.signature.Signature; +import org.opensaml.xml.util.DatatypeHelper; +import org.opensaml.xml.validation.ValidationException; +import org.opensaml.xml.validation.Validator; + +/** + * Checks {@link org.opensaml.xml.signature.Signature} for Schema compliance. + */ +public class SignatureSchemaValidator implements Validator { + + /** {@inheritDoc} */ + public void validate(Signature xmlObject) throws ValidationException { + validateSignatureMethod(xmlObject); + validateCanonicalizationMethod(xmlObject); + } + + /** + * Check the canonicalization method. + * + * @param xmlObject the object to be validated + * @throws ValidationException thrown if object is invalid + */ + protected void validateCanonicalizationMethod(Signature xmlObject) throws ValidationException { + if (DatatypeHelper.isEmpty(xmlObject.getCanonicalizationAlgorithm())) { + throw new ValidationException("The CanonicalizationMethod value was empty"); + } + } + + /** + * Check the signature method. + * + * @param xmlObject the object to be validated + * @throws ValidationException thrown if object is invalid + */ + protected void validateSignatureMethod(Signature xmlObject) throws ValidationException { + if (DatatypeHelper.isEmpty(xmlObject.getSignatureAlgorithm())) { + throw new ValidationException("The SignatureMethod value was empty"); + } + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/validator/TransformSchemaValidator.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/validator/TransformSchemaValidator.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/validator/TransformSchemaValidator.java 17 Aug 2012 15:17:04 -0000 1.1 @@ -0,0 +1,47 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature.validator; + +import org.opensaml.xml.signature.Transform; +import org.opensaml.xml.util.DatatypeHelper; +import org.opensaml.xml.validation.ValidationException; +import org.opensaml.xml.validation.Validator; + +/** + * Checks {@link org.opensaml.xml.signature.Transform} for Schema compliance. + */ +public class TransformSchemaValidator implements Validator { + + /** {@inheritDoc} */ + public void validate(Transform xmlObject) throws ValidationException { + validateAlgorithm(xmlObject); + } + + /** + * Validate the algorithm URI. + * + * @param xmlObject the object to validate + * @throws ValidationException thrown if the object is invalid + */ + protected void validateAlgorithm(Transform xmlObject) throws ValidationException { + if (DatatypeHelper.isEmpty(xmlObject.getAlgorithm())) { + throw new ValidationException("Transform algorithm URI was empty"); + } + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/validator/TransformsSchemaValidator.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/validator/TransformsSchemaValidator.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/validator/TransformsSchemaValidator.java 17 Aug 2012 15:17:04 -0000 1.1 @@ -0,0 +1,46 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature.validator; + +import org.opensaml.xml.signature.Transforms; +import org.opensaml.xml.validation.ValidationException; +import org.opensaml.xml.validation.Validator; + +/** + * Checks {@link org.opensaml.xml.signature.Transforms} for Schema compliance. + */ +public class TransformsSchemaValidator implements Validator { + + /** {@inheritDoc} */ + public void validate(Transforms xmlObject) throws ValidationException { + validateTransforms(xmlObject); + } + + /** + * Validate the transforms. + * + * @param xmlObject the object to validate + * @throws ValidationException thrown if the object is invalid + */ + protected void validateTransforms(Transforms xmlObject) throws ValidationException { + if (xmlObject.getTransforms().isEmpty()) { + throw new ValidationException("No Transform children were present in the Transforms object"); + } + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/validator/X509DataSchemaValidator.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/validator/X509DataSchemaValidator.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/validator/X509DataSchemaValidator.java 17 Aug 2012 15:17:04 -0000 1.1 @@ -0,0 +1,99 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature.validator; + +import java.util.HashSet; +import java.util.Set; + +import javax.xml.namespace.QName; + +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.signature.X509CRL; +import org.opensaml.xml.signature.X509Certificate; +import org.opensaml.xml.signature.X509Data; +import org.opensaml.xml.signature.X509IssuerSerial; +import org.opensaml.xml.signature.X509SKI; +import org.opensaml.xml.signature.X509SubjectName; +import org.opensaml.xml.util.XMLConstants; +import org.opensaml.xml.validation.ValidationException; +import org.opensaml.xml.validation.Validator; + +/** + * Checks {@link org.opensaml.xml.signature.X509Data} for Schema compliance. + */ +public class X509DataSchemaValidator implements Validator { + + /** QNames corresponding to the valid children. */ + private static final Set VALID_DS_CHILD_NAMES; + + /** {@inheritDoc} */ + public void validate(X509Data xmlObject) throws ValidationException { + validateChildrenPresence(xmlObject); + validateChildrenNamespaces(xmlObject); + } + + /** + * Get the QNames corresponding to the valid children + * defined in the XML Signature namespace. + * + * @return list of valid child QNames + */ + protected static Set getValidDSChildNames() { + return VALID_DS_CHILD_NAMES; + } + + /** + * Validate that at least child is present. + * + * @param xmlObject the object to validate + * @throws ValidationException thrown if the object is invalid + */ + protected void validateChildrenPresence(X509Data xmlObject) throws ValidationException { + if (xmlObject.getXMLObjects().isEmpty()) { + throw new ValidationException("No children were present in the X509Data object"); + } + } + + /** + * Validate that all children are either ones defined within the XML Signature schema, + * or are from another namespace. + * + * @param xmlObject the object to validate + * @throws ValidationException thrown if the object is invalid + */ + protected void validateChildrenNamespaces(X509Data xmlObject) throws ValidationException { + // Validate that any children are either the ones from the dsig schema, + // or are from another namespace. + for (XMLObject child : xmlObject.getXMLObjects()) { + QName childName = child.getElementQName(); + if (! getValidDSChildNames().contains(childName) + && XMLConstants.XMLSIG_NS.equals(childName.getNamespaceURI())) { + throw new ValidationException("X509Data contains an illegal child extension element: " + childName); + } + } + } + + static { + VALID_DS_CHILD_NAMES = new HashSet(10); + VALID_DS_CHILD_NAMES.add(X509IssuerSerial.DEFAULT_ELEMENT_NAME); + VALID_DS_CHILD_NAMES.add(X509SKI.DEFAULT_ELEMENT_NAME); + VALID_DS_CHILD_NAMES.add(X509SubjectName.DEFAULT_ELEMENT_NAME); + VALID_DS_CHILD_NAMES.add(X509Certificate.DEFAULT_ELEMENT_NAME); + VALID_DS_CHILD_NAMES.add(X509CRL.DEFAULT_ELEMENT_NAME); + } +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/validator/X509IssuerSerialSchemaValidator.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/validator/X509IssuerSerialSchemaValidator.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/validator/X509IssuerSerialSchemaValidator.java 17 Aug 2012 15:17:04 -0000 1.1 @@ -0,0 +1,49 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature.validator; + +import org.opensaml.xml.signature.X509IssuerSerial; +import org.opensaml.xml.validation.ValidationException; +import org.opensaml.xml.validation.Validator; + +/** + * Checks {@link org.opensaml.xml.signature.X509IssuerSerial} for Schema compliance. + */ +public class X509IssuerSerialSchemaValidator implements Validator { + + /** {@inheritDoc} */ + public void validate(X509IssuerSerial xmlObject) throws ValidationException { + validateChildrenPresence(xmlObject); + } + + /** + * Validate that exactly one child is present. + * + * @param xmlObject the object to validate + * @throws ValidationException thrown if the object is invalid + */ + protected void validateChildrenPresence(X509IssuerSerial xmlObject) throws ValidationException { + if (xmlObject.getX509IssuerName() == null) { + throw new ValidationException("X509IssuerSerial does not contain an X509IssuerName"); + } + if (xmlObject.getX509SerialNumber() == null) { + throw new ValidationException("X509IssuerSerial does not contain an X509SerialNumber"); + } + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/signature/validator/X509SerialNumberSchemaValidator.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/signature/validator/X509SerialNumberSchemaValidator.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/signature/validator/X509SerialNumberSchemaValidator.java 17 Aug 2012 15:17:04 -0000 1.1 @@ -0,0 +1,46 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.signature.validator; + +import org.opensaml.xml.signature.X509SerialNumber; +import org.opensaml.xml.validation.ValidationException; +import org.opensaml.xml.validation.Validator; + +/** + * Checks {@link org.opensaml.xml.signature.X509SerialNumber} for Schema compliance. + */ +public class X509SerialNumberSchemaValidator implements Validator { + + /** {@inheritDoc} */ + public void validate(X509SerialNumber xmlObject) throws ValidationException { + validateContent(xmlObject); + } + + /** + * Validate the serial number content. + * + * @param xmlObject the object to validate + * @throws ValidationException thrown if the object is invalid + */ + protected void validateContent(X509SerialNumber xmlObject) throws ValidationException { + if (xmlObject.getValue() == null) { + throw new ValidationException("X509SerialNumber did not contain a value"); + } + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/util/AbstractSimpleSingletonFactory.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/util/AbstractSimpleSingletonFactory.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/util/AbstractSimpleSingletonFactory.java 17 Aug 2012 15:17:17 -0000 1.1 @@ -0,0 +1,64 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.util; + +import java.util.WeakHashMap; + +/** + * A simple implementation of {@link SingletonFactory}. + * + *

+ * A {@link WeakHashMap} is used as the underlying store. This ensures that if the input class + * instance become otherwise unused (weakly reachable), the input class instance key used + * within the factory will not prevent the input class instance from being garbage-collected, + * thereby preventing a memory leak. + *

+ * + *

+ * NOTE: If the output class instance holds a strong or soft reference to the input class, + * do not use this factory. See instead {@link AbstractWrappedSingletonFactory}. Usage of this + * class in that scenario will result in a memory leak, as the input class instance will never + * become weakly reachable and therefore never garbage collected. + *

+ * + * + * @param the factory input class type + * @param the factory output class type + */ +public abstract class AbstractSimpleSingletonFactory + extends AbstractSingletonFactory { + + /** Storage for the factory. */ + private WeakHashMap map; + + /** Constructor. */ + public AbstractSimpleSingletonFactory() { + map = new WeakHashMap(); + } + + /** {@inheritDoc} */ + protected synchronized Output get(Input input) { + return map.get(input); + } + + /** {@inheritDoc} */ + protected synchronized void put(Input input, Output output) { + map.put(input, output); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/util/AbstractSingletonFactory.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/util/AbstractSingletonFactory.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/util/AbstractSingletonFactory.java 17 Aug 2012 15:17:17 -0000 1.1 @@ -0,0 +1,83 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.util; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * An abstract Template design pattern implementation of {@link SingletonFactory}. + * + * @param the factory input class type + * @param the factory output class type + */ +public abstract class AbstractSingletonFactory implements SingletonFactory { + + /** Class logger. */ + private final Logger log = LoggerFactory.getLogger(AbstractSingletonFactory.class); + + /** {@inheritDoc} */ + public synchronized Output getInstance(Input input) { + Output output = get(input); + if (output != null) { + log.trace("Input key mapped to a non-null value, returning output"); + return output; + } else { + log.trace("Input key mapped to a null value"); + } + + log.trace("Creating new output instance and inserting to factory map"); + output = createNewInstance(input); + if (output == null) { + log.error("New output instance was not created"); + return null; + } + + put(input, output); + + return output; + } + + /** + * Get the output instance currently associated with + * the input instance. + * + * @param input the input instance key + * @return the output instance which corresponds to the input instance, + * or null if not present + */ + protected abstract Output get(Input input); + + /** + * Store the input and output instance association. + * + * @param input the input instance key + * @param output the output instance value + */ + protected abstract void put(Input input, Output output); + + /** + * Create a new instance of the output class based on the input + * class instance. + * + * @param input the input class instance + * @return an output class instance + */ + protected abstract Output createNewInstance(Input input); + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/util/AbstractWrappedSingletonFactory.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/util/AbstractWrappedSingletonFactory.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/util/AbstractWrappedSingletonFactory.java 17 Aug 2012 15:17:17 -0000 1.1 @@ -0,0 +1,207 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.util; + +import java.lang.ref.WeakReference; +import java.util.HashSet; +import java.util.WeakHashMap; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * An implementation of {@link SingletonFactory}, which provides some support for handling + * cases where the output class instance holds a reference to the input class instance. + * + *

+ * A {@link WeakHashMap} is used as the underlying store. This ensures that if the input class + * instance become otherwise unused (weakly reachable), the input class instance key used + * within the factory will not prevent the input class from being garbage-collected, + * thereby preventing a memory leak. + *

+ * + *

+ * This class differs from {@link AbstractSimpleSingletonFactory} in that output value instances + * stored and returned by the factory are also wrapped internally in a {@link WeakReference}. + * This class should be used in cases where the output class holds a reference to the input + * class key, so as not to prevent the described weak reference-based garbage collection + * of the input class key, and thereby avoiding a memory leak. + *

+ * + *

+ * Because the output instance is held in a WeakReference, it is subject to aggressive + * garbage collection if it is otherwise weakly reachable (i.e. no strong or soft references + * to it are held outside of this factory), ostensibly defeating the purpose of this factory. + * Therefore if the lifecycle of external strong or soft references to any obtained output + * instances obtained from the factory is shorter than the desired lifecyle of the output instance + * (i.e. callers do not hold a strong or soft reference to an output instance for at least as + * long as to the input instance), then an option requireExplicitRelease is provided + * that causes the factory to internally maintain a strong reference to each output instance. + * This inhibits the garbage collection of the output instance. If this option is enabled, + * then callers must explicity indicate when the output instance may be garbage collected by + * calling {@link #release(Object)}. Failure to release an output instance when necessary + * will result in a memory leak of the output instance as well as the input instance (if + * the output instance holds a strong or soft reference to the input instance). + *

+ * + *

+ * The default value of requireExplicitRelease is false. This is appropriate + * for cases where calling code holds long-lived strong or soft references to the output instance, + * typically as long or longer than references to the corresponding input instance, or where explict release + * is undesirable or impractical. + *

+ * + *

+ * Subclasses of this class might also implement automatic release of output instances, + * instead of or in addition to, the explicit release mechanism supported by this class. + * This might be based for example on mechanisms such as object aging or a fixed size FIFO queue. + *

+ * + * @param the factory input class type + * @param the factory output class type + */ +public abstract class AbstractWrappedSingletonFactory + extends AbstractSingletonFactory { + + /** Class logger. */ + private final Logger log = LoggerFactory.getLogger(AbstractWrappedSingletonFactory.class); + + /** Storage for the factory. */ + private WeakHashMap> map; + + /** Set which holds a separate strong reference to output class instances, + * to inhibit garbage collection of the referent of the WeakReference. */ + private HashSet outputSet; + + /** Flag indicating whether explicit release of the output instances is required. */ + private boolean explicitRelease; + + /** Constructor. */ + public AbstractWrappedSingletonFactory() { + this(false); + } + + /** + * Constructor. + * + * @param requireExplicitRelease if true, callers must explicitly release + * output instances when garbage collection is desired. + */ + public AbstractWrappedSingletonFactory(boolean requireExplicitRelease) { + map = new WeakHashMap>(); + explicitRelease = requireExplicitRelease; + outputSet = new HashSet(); + } + + /** + * Obtain an instance of the output class based on an input class instance. + * + * @param input the input class instance + * @return an output class instance + */ + public synchronized Output getInstance(Input input) { + Output output = super.getInstance(input); + + if (explicitRelease && output != null) { + log.trace("Explicit release was indicated, registering output instance to inhibit garbage collection"); + register(output); + } + + return output; + } + + /** + * Get whether explict release of output instances is required, + * in order to allow garbage collection and prevent memory leaks. + * + * @return true if enabled, false otherwise + */ + public boolean isRequireExplicitRelease() { + return explicitRelease; + } + + /** + * Release the specified output instance so that, as the referent + * of a WeakReference, it may be garbage collected when it otherwise + * becomse weakly reachable. + * + * @param output the output instance to release + */ + public synchronized void release(Output output) { + outputSet.remove(output); + } + + /** + * Release all currently held output instances so they + * may be garbage collected when they become otherwise + * weakly reachable. + */ + public synchronized void releaseAll() { + outputSet.clear(); + } + + /** + * Register the output instance so as to inhibit garbage collection. + * + * @param output the ouput instance to register + */ + protected synchronized void register(Output output) { + outputSet.add(output); + } + + /** + * {@inheritDoc} + * + *

+ * The output instance will be automatically unwrapped from within the WeakReference. + *

+ * + *

+ * Note this will return null if either the input does not + * currently have an associated output, or if the WeakReference + * to the output stored had already been clearly in preparation + * for garbage collection. + *

+ */ + protected synchronized Output get(Input input) { + WeakReference outputRef = map.get(input); + if (outputRef != null) { + log.trace("Input key mapped to a non-null WeakReference"); + if (outputRef.get() != null) { + log.trace("WeakReference referent was non-null, returning referent"); + return outputRef.get(); + } else { + log.trace("WeakReference referent was null, removing WeakReference entry from map"); + map.remove(input); + } + } + return null; + } + + /** + * {@inheritDoc} + * + *

+ * The output instance will be automatically wrapped in a WeakReference. + *

+ */ + protected synchronized void put(Input input, Output output) { + map.put(input, new WeakReference(output)); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/util/AttributeMap.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/util/AttributeMap.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/util/AttributeMap.java 17 Aug 2012 15:17:17 -0000 1.1 @@ -0,0 +1,526 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.util; + +import java.util.Collection; +import java.util.Collections; +import java.util.Map; +import java.util.Set; + +import javax.xml.namespace.QName; + +import net.jcip.annotations.NotThreadSafe; + +import org.opensaml.xml.Configuration; +import org.opensaml.xml.NamespaceManager; +import org.opensaml.xml.XMLObject; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * A map of attribute names and attribute values that invalidates the DOM of the attribute owning XMLObject when the + * attributes change. + * + * Note: + */ +@NotThreadSafe +public class AttributeMap implements Map { + + /** Logger. */ + private final Logger log = LoggerFactory.getLogger(AttributeMap.class); + + /** XMLObject owning the attributes. */ + private XMLObject attributeOwner; + + /** Map of attributes. */ + private Map attributes; + + /** Set of attribute QNames which have been locally registered as having an ID type within this + * AttributeMap instance. */ + private Set idAttribNames; + + /** Set of attribute QNames which have been locally registered as having an QName value type within this + * AttributeMap instance. */ + private Set qnameAttribNames; + + /** Flag indicating whether an attempt should be made to infer QName values, + * if attribute is not registered as a QName type. */ + private boolean inferQNameValues; + + /** + * Constructor. + * + * @param newOwner the XMLObject that owns these attributes + * + * @throws NullPointerException thrown if the given XMLObject is null + */ + public AttributeMap(XMLObject newOwner) throws NullPointerException { + if (newOwner == null) { + throw new NullPointerException("Attribute owner XMLObject may not be null"); + } + + attributeOwner = newOwner; + attributes = new LazyMap(); + idAttribNames = new LazySet(); + qnameAttribNames = new LazySet(); + } + + /** {@inheritDoc} */ + public String put(QName attributeName, String value) { + String oldValue = get(attributeName); + if (value != oldValue) { + releaseDOM(); + attributes.put(attributeName, value); + if (isIDAttribute(attributeName) || Configuration.isIDAttribute(attributeName)) { + attributeOwner.getIDIndex().deregisterIDMapping(oldValue); + attributeOwner.getIDIndex().registerIDMapping(value, attributeOwner); + } + if (!DatatypeHelper.isEmpty(attributeName.getNamespaceURI())) { + if (value == null) { + attributeOwner.getNamespaceManager().deregisterAttributeName(attributeName); + } else { + attributeOwner.getNamespaceManager().registerAttributeName(attributeName); + } + } + checkAndDeregisterQNameValue(attributeName, oldValue); + checkAndRegisterQNameValue(attributeName, value); + } + + return oldValue; + } + + /** + * Set an attribute value as a QName. This method takes care of properly registering and + * deregistering the namespace information associated with the new QName being added, and + * with the old QName being possibly removed. + * + * @param attributeName the attribute name + * @param value the QName attribute value + * @return the old attribute value, possibly null + */ + public QName put(QName attributeName, QName value) { + String oldValueString = get(attributeName); + + QName oldValue = null; + if (!DatatypeHelper.isEmpty(oldValueString)) { + oldValue = resolveQName(oldValueString, true); + } + + if (!DatatypeHelper.safeEquals(oldValue, value)) { + releaseDOM(); + if (value != null) { + // new value is not null, old value was either null or non-equal + String newStringValue = constructAttributeValue(value); + attributes.put(attributeName, newStringValue); + registerQNameValue(attributeName, value); + attributeOwner.getNamespaceManager().registerAttributeName(attributeName); + } else { + // new value is null, old value was not null + deregisterQNameValue(attributeName); + attributeOwner.getNamespaceManager().deregisterAttributeName(attributeName); + } + } + + return oldValue; + } + + /** {@inheritDoc} */ + public void clear() { + LazySet keys = new LazySet(); + keys.addAll(attributes.keySet()); + for (QName attributeName : keys) { + remove(attributeName); + } + } + + /** + * Returns the set of keys. + * + * @return unmodifiable set of keys + */ + public Set keySet() { + return Collections.unmodifiableSet(attributes.keySet()); + } + + /** {@inheritDoc} */ + public int size() { + return attributes.size(); + } + + /** {@inheritDoc} */ + public boolean isEmpty() { + return attributes.isEmpty(); + } + + /** {@inheritDoc} */ + public boolean containsKey(Object key) { + return attributes.containsKey(key); + } + + /** {@inheritDoc} */ + public boolean containsValue(Object value) { + return attributes.containsValue(value); + } + + /** {@inheritDoc} */ + public String get(Object key) { + return attributes.get(key); + } + + /** {@inheritDoc} */ + public String remove(Object key) { + String removedValue = attributes.remove(key); + if (removedValue != null) { + releaseDOM(); + QName attributeName = (QName) key; + if (isIDAttribute(attributeName) || Configuration.isIDAttribute(attributeName)) { + attributeOwner.getIDIndex().deregisterIDMapping(removedValue); + } + attributeOwner.getNamespaceManager().deregisterAttributeName(attributeName); + checkAndDeregisterQNameValue(attributeName, removedValue); + } + + return removedValue; + } + + /** {@inheritDoc} */ + public void putAll(Map t) { + if (t != null && t.size() > 0) { + for (Entry entry : t.entrySet()) { + put(entry.getKey(), entry.getValue()); + } + } + } + + /** + * Returns the values in this map. + * + * @return an unmodifiable collection of values + */ + public Collection values() { + return Collections.unmodifiableCollection(attributes.values()); + } + + /** + * Returns the set of entries. + * + * @return unmodifiable set of entries + */ + public Set> entrySet() { + return Collections.unmodifiableSet(attributes.entrySet()); + } + + /** + * Register an attribute as having a type of ID. + * + * @param attributeName the QName of the ID attribute to be registered + */ + public void registerID(QName attributeName) { + if (! idAttribNames.contains(attributeName)) { + idAttribNames.add(attributeName); + } + + // In case attribute already has a value, + // register the current value mapping with the XMLObject owner. + if (containsKey(attributeName)) { + attributeOwner.getIDIndex().registerIDMapping(get(attributeName), attributeOwner); + } + } + + /** + * Deregister an attribute as having a type of ID. + * + * @param attributeName the QName of the ID attribute to be de-registered + */ + public void deregisterID(QName attributeName) { + if (idAttribNames.contains(attributeName)) { + idAttribNames.remove(attributeName); + } + + // In case attribute already has a value, + // deregister the current value mapping with the XMLObject owner. + if (containsKey(attributeName)) { + attributeOwner.getIDIndex().deregisterIDMapping(get(attributeName)); + } + } + + /** + * Check whether a given attribute is locally registered as having an ID type within + * this AttributeMap instance. + * + * @param attributeName the QName of the attribute to be checked for ID type. + * @return true if attribute is registered as having an ID type. + */ + public boolean isIDAttribute(QName attributeName) { + return idAttribNames.contains(attributeName); + } + + /** + * Register an attribute as having a type of QName. + * + * @param attributeName the name of the QName-valued attribute to be registered + */ + public void registerQNameAttribute(QName attributeName) { + qnameAttribNames.add(attributeName); + } + + /** + * Deregister an attribute as having a type of QName. + * + * @param attributeName the name of the QName-valued attribute to be registered + */ + public void deregisterQNameAttribute(QName attributeName) { + qnameAttribNames.remove(attributeName); + } + + /** + * Check whether a given attribute is known to have a QName type. + * + * @param attributeName the QName of the attribute to be checked for QName type. + * @return true if attribute is registered as having an QName type. + */ + public boolean isQNameAttribute(QName attributeName) { + return qnameAttribNames.contains(attributeName); + } + + /** + * Get the flag indicating whether an attempt should be made to infer QName values, + * if attribute is not registered via a configuration as a QName type. Default is false. + * + * @return true if QName types should be inferred, false if not + * + */ + public boolean isInferQNameValues() { + return inferQNameValues; + } + + /** + * Set the flag indicating whether an attempt should be made to infer QName values, + * if attribute is not registered via a configuration as a QName type. Default is false. + * + * @param flag true if QName types should be inferred, false if not + * + */ + public void setInferQNameValues(boolean flag) { + inferQNameValues = flag; + } + + /** + * Releases the DOM caching associated XMLObject and its ancestors. + */ + private void releaseDOM() { + attributeOwner.releaseDOM(); + attributeOwner.releaseParentDOM(true); + } + + /** + * Check whether the attribute value is a QName type, and if it is, + * register it with the owner's namespace manger. + * + * @param attributeName the attribute name + * @param attributeValue the attribute value + */ + private void checkAndRegisterQNameValue(QName attributeName, String attributeValue) { + if (attributeValue == null) { + return; + } + + QName qnameValue = checkQName(attributeName, attributeValue); + if (qnameValue != null) { + log.trace("Attribute '{}' with value '{}' was evaluated to be QName type", + attributeName, attributeValue); + registerQNameValue(attributeName, qnameValue); + } else { + log.trace("Attribute '{}' with value '{}' was not evaluated to be QName type", + attributeName, attributeValue); + } + + } + + /** + * Register a QName attribute value with the owner's namespace manger. + * + * @param attributeName the attribute name + * @param attributeValue the attribute value + */ + private void registerQNameValue(QName attributeName, QName attributeValue) { + if (attributeValue == null) { + return; + } + + String attributeID = NamespaceManager.generateAttributeID(attributeName); + log.trace("Registering QName attribute value '{}' under attibute ID '{}'", + attributeValue, attributeID); + attributeOwner.getNamespaceManager().registerAttributeValue(attributeID, attributeValue); + } + + /** + * Check whether the attribute value is a QName type, and if it is, + * deregister it with the owner's namespace manger. + * + * @param attributeName the attribute name + * @param attributeValue the attribute value + */ + private void checkAndDeregisterQNameValue(QName attributeName, String attributeValue) { + if (attributeValue == null) { + return; + } + + QName qnameValue = checkQName(attributeName, attributeValue); + if (qnameValue != null) { + log.trace("Attribute '{}' with value '{}' was evaluated to be QName type", + attributeName, attributeValue); + deregisterQNameValue(attributeName); + } else { + log.trace("Attribute '{}' with value '{}' was not evaluated to be QName type", + attributeName, attributeValue); + } + } + + /** + * Deregister a QName attribute value with the owner's namespace manger. + * + * @param attributeName the attribute name whose QName attribute value should be deregistered + */ + private void deregisterQNameValue(QName attributeName) { + String attributeID = NamespaceManager.generateAttributeID(attributeName); + log.trace("Deregistering QName attribute with attibute ID '{}'", attributeID); + attributeOwner.getNamespaceManager().deregisterAttributeValue(attributeID); + } + + /** + * Check where the attribute value is a QName type, and if so, return the QName. + * + * @param attributeName the attribute name + * @param attributeValue the attribute value + * @return the QName if the attribute value is a QName type, otherwise null + */ + private QName checkQName(QName attributeName, String attributeValue) { + log.trace("Checking whether attribute '{}' with value {} is a QName type", attributeName, attributeValue); + + if (attributeValue == null) { + log.trace("Attribute value was null, returning null"); + return null; + } + + if (isQNameAttribute(attributeName)) { + log.trace("Configuration indicates attribute with name '{}' is a QName type, resolving value QName", + attributeName); + // Do support the default namespace in this scenario, since we know it should be a QName + QName valueName = resolveQName(attributeValue, true); + if (valueName != null) { + log.trace("Successfully resolved attribute value to QName: {}", valueName); + } else { + log.trace("Could not resolve attribute value to QName, returning null"); + } + return valueName; + } else if (isInferQNameValues()) { + log.trace("Attempting to infer whether attribute value is a QName"); + // Do not support the default namespace in this scenario, since we're trying to infer. + // Better to fail to resolve than to infer a bogus QName value. + QName valueName = resolveQName(attributeValue, false); + if (valueName != null) { + log.trace("Resolved attribute as a QName: '{}'", valueName); + } else { + log.trace("Attribute value was not resolveable to a QName, returning null"); + } + return valueName; + } else { + log.trace("Attribute was not registered in configuration as a QName type and QName inference is disabled"); + return null; + } + + } + + /** + * Attempt to resolve the specified attribute value into a QName. + * + * @param attributeValue the value to evaluate + * @param isDefaultNSOK flag indicating whether resolution should be attempted if the prefix is null, + * that is, the value is considered to be be potentially in the default XML namespace + * + * @return the QName, or null if unable to resolve into a QName + */ + private QName resolveQName(String attributeValue, boolean isDefaultNSOK) { + if (attributeValue == null) { + return null; + } + log.trace("Attemtping to resolve QName from attribute value '{}'", attributeValue); + + // Attempt to resolve value as a QName by splitting on colon and then attempting to resolve + // this candidate prefix into a namespace URI. + String candidatePrefix = null; + String localPart = null; + int ci = attributeValue.indexOf(':'); + if (ci > -1) { + candidatePrefix = attributeValue.substring(0, ci); + log.trace("Evaluating candiate namespace prefix '{}'", candidatePrefix); + localPart = attributeValue.substring(ci+1); + } else { + // No prefix - possibly evaluate as if in the default namespace + if (isDefaultNSOK) { + candidatePrefix = null; + log.trace("Value did not contain a colon, evaluating as default namespace"); + localPart = attributeValue; + } else { + log.trace("Value did not contain a colon, default namespace is disallowed, returning null"); + return null; + } + } + + log.trace("Evaluated QName local part as '{}'", localPart); + + String nsURI = XMLObjectHelper.lookupNamespaceURI(attributeOwner, candidatePrefix); + log.trace("Resolved namespace URI '{}'", nsURI); + if (nsURI != null) { + QName name = XMLHelper.constructQName(nsURI, localPart, candidatePrefix); + log.trace("Resolved QName '{}'", name); + return name; + } else { + log.trace("Namespace URI for candidate prefix '{}' could not be resolved", candidatePrefix); + } + + log.trace("Value was either not a QName, or namespace URI could not be resolved"); + + return null; + } + + /** + * Construct the string representation of a QName attribute value. + * + * @param attributeValue the QName to process + * @return the attribute value string representation of the QName + */ + private String constructAttributeValue(QName attributeValue) { + String trimmedLocalName = DatatypeHelper.safeTrimOrNullString(attributeValue.getLocalPart()); + + if (trimmedLocalName == null) { + throw new IllegalArgumentException("Local name may not be null or empty"); + } + + String qualifiedName; + String trimmedPrefix = DatatypeHelper.safeTrimOrNullString(attributeValue.getPrefix()); + if (trimmedPrefix != null) { + qualifiedName = trimmedPrefix + ":" + DatatypeHelper.safeTrimOrNullString(trimmedLocalName); + } else { + qualifiedName = DatatypeHelper.safeTrimOrNullString(trimmedLocalName); + } + return qualifiedName; + } + +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/util/Base64.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/util/Base64.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/util/Base64.java 17 Aug 2012 15:17:17 -0000 1.1 @@ -0,0 +1,1293 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.util; + +/** + * Encodes and decodes to and from Base64 notation. + * + *

+ * Change Log: + *

+ *
    + *
  • v2.1 - Cleaned up javadoc comments and unused variables and methods. Added some convenience methods for reading + * and writing to and from files.
  • + *
  • v2.0.2 - Now specifies UTF-8 encoding in places where the code fails on systems with other encodings (like + * EBCDIC).
  • + *
  • v2.0.1 - Fixed an error when decoding a single byte, that is, when the encoded data was a single byte.
  • + *
  • v2.0 - I got rid of methods that used booleans to set options. Now everything is more consolidated and cleaner. + * The code now detects when data that's being decoded is gzip-compressed and will decompress it automatically. + * Generally things are cleaner. You'll probably have to change some method calls that you were making to support the + * new options format (ints that you "OR" together).
  • + *
  • v1.5.1 - Fixed bug when decompressing and decoding to a byte[] using + * decode( String s, boolean gzipCompressed ). Added the ability to "suspend" encoding in the Output Stream + * so you can turn on and off the encoding if you need to embed base64 data in an otherwise "normal" stream (like an XML + * file).
  • + *
  • v1.5 - Output stream pases on flush() command but doesn't do anything itself. This helps when using GZIP + * streams. Added the ability to GZip-compress objects before encoding them.
  • + *
  • v1.4 - Added helper methods to read/write files.
  • + *
  • v1.3.6 - Fixed OutputStream.flush() so that 'position' is reset.
  • + *
  • v1.3.5 - Added flag to turn on and off line breaks. Fixed bug in input stream where last buffer being read, if + * not completely full, was not returned.
  • + *
  • v1.3.4 - Fixed when "improperly padded stream" error was thrown at the wrong time.
  • + *
  • v1.3.3 - Fixed I/O streams which were totally messed up.
  • + *
+ * + *

+ * I am placing this code in the Public Domain. Do with it as you will. This software comes with no guarantees or + * warranties but with plenty of well-wishing instead! Please visit http://iharder.net/base64 periodically to check for updates or to contribute + * improvements. + *

+ * + * @author Robert Harder + * @author rob@iharder.net + * @version 2.1 + */ +public class Base64 { + + /* ******** P U B L I C F I E L D S ******** */ + + /** No options specified. Value is zero. */ + public final static int NO_OPTIONS = 0; + + /** Specify encoding. */ + public final static int ENCODE = 1; + + /** Specify decoding. */ + public final static int DECODE = 0; + + /** Specify that data should be gzip-compressed. */ + public final static int GZIP = 2; + + /** Don't break lines when encoding (violates strict Base64 specification) */ + public final static int DONT_BREAK_LINES = 8; + + /* ******** P R I V A T E F I E L D S ******** */ + + /** Maximum line length (76) of Base64 output. */ + private final static int MAX_LINE_LENGTH = 76; + + /** The equals sign (=) as a byte. */ + private final static byte EQUALS_SIGN = (byte) '='; + + /** The new line character (\n) as a byte. */ + private final static byte NEW_LINE = (byte) '\n'; + + /** Preferred encoding. */ + private final static String PREFERRED_ENCODING = "UTF-8"; + + /** The 64 valid Base64 values. */ + private final static byte[] ALPHABET; + + private final static byte[] _NATIVE_ALPHABET = /* May be something funny like EBCDIC */ + { (byte) 'A', (byte) 'B', (byte) 'C', (byte) 'D', (byte) 'E', (byte) 'F', (byte) 'G', (byte) 'H', (byte) 'I', + (byte) 'J', (byte) 'K', (byte) 'L', (byte) 'M', (byte) 'N', (byte) 'O', (byte) 'P', (byte) 'Q', (byte) 'R', + (byte) 'S', (byte) 'T', (byte) 'U', (byte) 'V', (byte) 'W', (byte) 'X', (byte) 'Y', (byte) 'Z', (byte) 'a', + (byte) 'b', (byte) 'c', (byte) 'd', (byte) 'e', (byte) 'f', (byte) 'g', (byte) 'h', (byte) 'i', (byte) 'j', + (byte) 'k', (byte) 'l', (byte) 'm', (byte) 'n', (byte) 'o', (byte) 'p', (byte) 'q', (byte) 'r', (byte) 's', + (byte) 't', (byte) 'u', (byte) 'v', (byte) 'w', (byte) 'x', (byte) 'y', (byte) 'z', (byte) '0', (byte) '1', + (byte) '2', (byte) '3', (byte) '4', (byte) '5', (byte) '6', (byte) '7', (byte) '8', (byte) '9', (byte) '+', + (byte) '/' }; + + /** Determine which ALPHABET to use. */ + static { + byte[] __bytes; + try { + __bytes = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".getBytes(PREFERRED_ENCODING); + } // end try + catch (java.io.UnsupportedEncodingException use) { + __bytes = _NATIVE_ALPHABET; // Fall back to native encoding + } // end catch + ALPHABET = __bytes; + } // end static + + /** + * Translates a Base64 value to either its 6-bit reconstruction value or a negative number indicating some other + * meaning. + */ + private final static byte[] DECODABET = { -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 0 - 8 + -5, -5, // Whitespace: Tab and Linefeed + -9, -9, // Decimal 11 - 12 + -5, // Whitespace: Carriage Return + -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 14 - 26 + -9, -9, -9, -9, -9, // Decimal 27 - 31 + -5, // Whitespace: Space + -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 33 - 42 + 62, // Plus sign at decimal 43 + -9, -9, -9, // Decimal 44 - 46 + 63, // Slash at decimal 47 + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, // Numbers zero through nine + -9, -9, -9, // Decimal 58 - 60 + -1, // Equals sign at decimal 61 + -9, -9, -9, // Decimal 62 - 64 + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, // Letters 'A' through 'N' + 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, // Letters 'O' through 'Z' + -9, -9, -9, -9, -9, -9, // Decimal 91 - 96 + 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, // Letters 'a' through 'm' + 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, // Letters 'n' through 'z' + -9, -9, -9, -9 // Decimal 123 - 126 + /* + * ,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 127 - 139 -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal + * 140 - 152 -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 153 - 165 -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // + * Decimal 166 - 178 -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 179 - 191 + * -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 192 - 204 -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal + * 205 - 217 -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 218 - 230 -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // + * Decimal 231 - 243 -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9 // Decimal 244 - 255 + */ + }; + + // I think I end up not using the BAD_ENCODING indicator. + // private final static byte BAD_ENCODING = -9; // Indicates error in encoding + private final static byte WHITE_SPACE_ENC = -5; // Indicates white space in encoding + + private final static byte EQUALS_SIGN_ENC = -1; // Indicates equals sign in encoding + + /** Defeats instantiation. */ + private Base64() { + } + + /* ******** E N C O D I N G M E T H O D S ******** */ + + /** + * Encodes up to the first three bytes of array threeBytes and returns a four-byte array in Base64 + * notation. The actual number of significant bytes in your array is given by numSigBytes. The array + * threeBytes needs only be as big as numSigBytes. Code can reuse a byte array by passing a + * four-byte array as b4. + * + * @param b4 A reusable byte array to reduce array instantiation + * @param threeBytes the array to convert + * @param numSigBytes the number of significant bytes in your array + * @return four byte array in Base64 notation. + * @since 1.5.1 + */ + private static byte[] encode3to4(byte[] b4, byte[] threeBytes, int numSigBytes) { + encode3to4(threeBytes, 0, numSigBytes, b4, 0); + return b4; + } // end encode3to4 + + /** + * Encodes up to three bytes of the array source and writes the resulting four Base64 bytes to + * destination. The source and destination arrays can be manipulated anywhere along their length by + * specifying srcOffset and destOffset. This method does not check to make sure your arrays + * are large enough to accomodate srcOffset + 3 for the source array or destOffset + + * 4 for the destination array. The actual number of significant bytes in your array is given by + * numSigBytes. + * + * @param source the array to convert + * @param srcOffset the index where conversion begins + * @param numSigBytes the number of significant bytes in your array + * @param destination the array to hold the conversion + * @param destOffset the index where output will be put + * @return the destination array + * @since 1.3 + */ + private static byte[] encode3to4(byte[] source, int srcOffset, int numSigBytes, byte[] destination, int destOffset) { + // 1 2 3 + // 01234567890123456789012345678901 Bit position + // --------000000001111111122222222 Array position from threeBytes + // --------| || || || | Six bit groups to index ALPHABET + // >>18 >>12 >> 6 >> 0 Right shift necessary + // 0x3f 0x3f 0x3f Additional AND + + // Create buffer with zero-padding if there are only one or two + // significant bytes passed in the array. + // We have to shift left 24 in order to flush out the 1's that appear + // when Java treats a value as negative that is cast from a byte to an int. + int inBuff = (numSigBytes > 0 ? ((source[srcOffset] << 24) >>> 8) : 0) + | (numSigBytes > 1 ? ((source[srcOffset + 1] << 24) >>> 16) : 0) + | (numSigBytes > 2 ? ((source[srcOffset + 2] << 24) >>> 24) : 0); + + switch (numSigBytes) { + case 3: + destination[destOffset] = ALPHABET[(inBuff >>> 18)]; + destination[destOffset + 1] = ALPHABET[(inBuff >>> 12) & 0x3f]; + destination[destOffset + 2] = ALPHABET[(inBuff >>> 6) & 0x3f]; + destination[destOffset + 3] = ALPHABET[(inBuff) & 0x3f]; + return destination; + + case 2: + destination[destOffset] = ALPHABET[(inBuff >>> 18)]; + destination[destOffset + 1] = ALPHABET[(inBuff >>> 12) & 0x3f]; + destination[destOffset + 2] = ALPHABET[(inBuff >>> 6) & 0x3f]; + destination[destOffset + 3] = EQUALS_SIGN; + return destination; + + case 1: + destination[destOffset] = ALPHABET[(inBuff >>> 18)]; + destination[destOffset + 1] = ALPHABET[(inBuff >>> 12) & 0x3f]; + destination[destOffset + 2] = EQUALS_SIGN; + destination[destOffset + 3] = EQUALS_SIGN; + return destination; + + default: + return destination; + } // end switch + } // end encode3to4 + + /** + * Serializes an object and returns the Base64-encoded version of that serialized object. If the object cannot be + * serialized or there is another error, the method will return null. The object is not GZip-compressed + * before being encoded. + * + * @param serializableObject The object to encode + * @return The Base64-encoded object + * @since 1.4 + */ + public static String encodeObject(java.io.Serializable serializableObject) { + return encodeObject(serializableObject, NO_OPTIONS); + } // end encodeObject + + /** + * Serializes an object and returns the Base64-encoded version of that serialized object. If the object cannot be + * serialized or there is another error, the method will return null. + *

+ * Valid options: + * + *

+     *       GZIP: gzip-compresses object before encoding it.
+     *       DONT_BREAK_LINES: don't break lines at 76 characters
+     *         <i>Note: Technically, this makes your encoding non-compliant.</i>
+     * 
+ * + *

+ * Example: encodeObject( myObj, Base64.GZIP ) or + *

+ * Example: encodeObject( myObj, Base64.GZIP | Base64.DONT_BREAK_LINES ) + * + * @param serializableObject The object to encode + * @param options Specified options + * @return The Base64-encoded object + * @see Base64#GZIP + * @see Base64#DONT_BREAK_LINES + * @since 2.0 + */ + public static String encodeObject(java.io.Serializable serializableObject, int options) { + // Streams + java.io.ByteArrayOutputStream baos = null; + java.io.OutputStream b64os = null; + java.io.ObjectOutputStream oos = null; + java.util.zip.GZIPOutputStream gzos = null; + + // Isolate options + int gzip = (options & GZIP); + int dontBreakLines = (options & DONT_BREAK_LINES); + + try { + // ObjectOutputStream -> (GZIP) -> Base64 -> ByteArrayOutputStream + baos = new java.io.ByteArrayOutputStream(); + b64os = new Base64.OutputStream(baos, ENCODE | dontBreakLines); + + // GZip? + if (gzip == GZIP) { + gzos = new java.util.zip.GZIPOutputStream(b64os); + oos = new java.io.ObjectOutputStream(gzos); + } // end if: gzip + else + oos = new java.io.ObjectOutputStream(b64os); + + oos.writeObject(serializableObject); + } // end try + catch (java.io.IOException e) { + e.printStackTrace(); + return null; + } // end catch + finally { + try { + oos.close(); + } catch (Exception e) { + } + try { + gzos.close(); + } catch (Exception e) { + } + try { + b64os.close(); + } catch (Exception e) { + } + try { + baos.close(); + } catch (Exception e) { + } + } // end finally + + // Return value according to relevant encoding. + try { + return new String(baos.toByteArray(), PREFERRED_ENCODING); + } // end try + catch (java.io.UnsupportedEncodingException uue) { + return new String(baos.toByteArray()); + } // end catch + + } // end encode + + /** + * Encodes a byte array into Base64 notation. Does not GZip-compress data. + * + * @param source The data to convert + * @since 1.4 + */ + public static String encodeBytes(byte[] source) { + return encodeBytes(source, 0, source.length, NO_OPTIONS); + } // end encodeBytes + + /** + * Encodes a byte array into Base64 notation. + *

+ * Valid options: + * + *

+     *       GZIP: gzip-compresses object before encoding it.
+     *       DONT_BREAK_LINES: don't break lines at 76 characters
+     *         <i>Note: Technically, this makes your encoding non-compliant.</i>
+     * 
+ * + *

+ * Example: encodeBytes( myData, Base64.GZIP ) or + *

+ * Example: encodeBytes( myData, Base64.GZIP | Base64.DONT_BREAK_LINES ) + * + * + * @param source The data to convert + * @param options Specified options + * @see Base64#GZIP + * @see Base64#DONT_BREAK_LINES + * @since 2.0 + */ + public static String encodeBytes(byte[] source, int options) { + return encodeBytes(source, 0, source.length, options); + } // end encodeBytes + + /** + * Encodes a byte array into Base64 notation. Does not GZip-compress data. + * + * @param source The data to convert + * @param off Offset in array where conversion should begin + * @param len Length of data to convert + * @since 1.4 + */ + public static String encodeBytes(byte[] source, int off, int len) { + return encodeBytes(source, off, len, NO_OPTIONS); + } // end encodeBytes + + /** + * Encodes a byte array into Base64 notation. + *

+ * Valid options: + * + *

+     *       GZIP: gzip-compresses object before encoding it.
+     *       DONT_BREAK_LINES: don't break lines at 76 characters
+     *         <i>Note: Technically, this makes your encoding non-compliant.</i>
+     * 
+ * + *

+ * Example: encodeBytes( myData, Base64.GZIP ) or + *

+ * Example: encodeBytes( myData, Base64.GZIP | Base64.DONT_BREAK_LINES ) + * + * + * @param source The data to convert + * @param off Offset in array where conversion should begin + * @param len Length of data to convert + * @param options Specified options + * @see Base64#GZIP + * @see Base64#DONT_BREAK_LINES + * @since 2.0 + */ + public static String encodeBytes(byte[] source, int off, int len, int options) { + // Isolate options + int dontBreakLines = (options & DONT_BREAK_LINES); + int gzip = (options & GZIP); + + // Compress? + if (gzip == GZIP) { + java.io.ByteArrayOutputStream baos = null; + java.util.zip.GZIPOutputStream gzos = null; + Base64.OutputStream b64os = null; + + try { + // GZip -> Base64 -> ByteArray + baos = new java.io.ByteArrayOutputStream(); + b64os = new Base64.OutputStream(baos, ENCODE | dontBreakLines); + gzos = new java.util.zip.GZIPOutputStream(b64os); + + gzos.write(source, off, len); + gzos.close(); + } // end try + catch (java.io.IOException e) { + e.printStackTrace(); + return null; + } // end catch + finally { + try { + gzos.close(); + } catch (Exception e) { + } + try { + b64os.close(); + } catch (Exception e) { + } + try { + baos.close(); + } catch (Exception e) { + } + } // end finally + + // Return value according to relevant encoding. + try { + return new String(baos.toByteArray(), PREFERRED_ENCODING); + } // end try + catch (java.io.UnsupportedEncodingException uue) { + return new String(baos.toByteArray()); + } // end catch + } // end if: compress + + // Else, don't compress. Better not to use streams at all then. + else { + // Convert option to boolean in way that code likes it. + boolean breakLines = dontBreakLines == 0; + + int len43 = len * 4 / 3; + byte[] outBuff = new byte[(len43) // Main 4:3 + + ((len % 3) > 0 ? 4 : 0) // Account for padding + + (breakLines ? (len43 / MAX_LINE_LENGTH) : 0)]; // New lines + int d = 0; + int e = 0; + int len2 = len - 2; + int lineLength = 0; + for (; d < len2; d += 3, e += 4) { + encode3to4(source, d + off, 3, outBuff, e); + + lineLength += 4; + if (breakLines && lineLength == MAX_LINE_LENGTH) { + outBuff[e + 4] = NEW_LINE; + e++; + lineLength = 0; + } // end if: end of line + } // en dfor: each piece of array + + if (d < len) { + encode3to4(source, d + off, len - d, outBuff, e); + e += 4; + } // end if: some padding needed + + // Return value according to relevant encoding. + try { + return new String(outBuff, 0, e, PREFERRED_ENCODING); + } // end try + catch (java.io.UnsupportedEncodingException uue) { + return new String(outBuff, 0, e); + } // end catch + + } // end else: don't compress + + } // end encodeBytes + + /* ******** D E C O D I N G M E T H O D S ******** */ + + /** + * Decodes four bytes from array source and writes the resulting bytes (up to three of them) to + * destination. The source and destination arrays can be manipulated anywhere along their length by + * specifying srcOffset and destOffset. This method does not check to make sure your arrays + * are large enough to accomodate srcOffset + 4 for the source array or destOffset + + * 3 for the destination array. This method returns the actual number of bytes that were converted from + * the Base64 encoding. + * + * + * @param source the array to convert + * @param srcOffset the index where conversion begins + * @param destination the array to hold the conversion + * @param destOffset the index where output will be put + * @return the number of decoded bytes converted + * @since 1.3 + */ + private static int decode4to3(byte[] source, int srcOffset, byte[] destination, int destOffset) { + // Example: Dk== + if (source[srcOffset + 2] == EQUALS_SIGN) { + // Two ways to do the same thing. Don't know which way I like best. + // int outBuff = ( ( DECODABET[ source[ srcOffset ] ] << 24 ) >>> 6 ) + // | ( ( DECODABET[ source[ srcOffset + 1] ] << 24 ) >>> 12 ); + int outBuff = ((DECODABET[source[srcOffset]] & 0xFF) << 18) + | ((DECODABET[source[srcOffset + 1]] & 0xFF) << 12); + + destination[destOffset] = (byte) (outBuff >>> 16); + return 1; + } + + // Example: DkL= + else if (source[srcOffset + 3] == EQUALS_SIGN) { + // Two ways to do the same thing. Don't know which way I like best. + // int outBuff = ( ( DECODABET[ source[ srcOffset ] ] << 24 ) >>> 6 ) + // | ( ( DECODABET[ source[ srcOffset + 1 ] ] << 24 ) >>> 12 ) + // | ( ( DECODABET[ source[ srcOffset + 2 ] ] << 24 ) >>> 18 ); + int outBuff = ((DECODABET[source[srcOffset]] & 0xFF) << 18) + | ((DECODABET[source[srcOffset + 1]] & 0xFF) << 12) + | ((DECODABET[source[srcOffset + 2]] & 0xFF) << 6); + + destination[destOffset] = (byte) (outBuff >>> 16); + destination[destOffset + 1] = (byte) (outBuff >>> 8); + return 2; + } + + // Example: DkLE + else { + try { + // Two ways to do the same thing. Don't know which way I like best. + // int outBuff = ( ( DECODABET[ source[ srcOffset ] ] << 24 ) >>> 6 ) + // | ( ( DECODABET[ source[ srcOffset + 1 ] ] << 24 ) >>> 12 ) + // | ( ( DECODABET[ source[ srcOffset + 2 ] ] << 24 ) >>> 18 ) + // | ( ( DECODABET[ source[ srcOffset + 3 ] ] << 24 ) >>> 24 ); + int outBuff = ((DECODABET[source[srcOffset]] & 0xFF) << 18) + | ((DECODABET[source[srcOffset + 1]] & 0xFF) << 12) + | ((DECODABET[source[srcOffset + 2]] & 0xFF) << 6) + | ((DECODABET[source[srcOffset + 3]] & 0xFF)); + + destination[destOffset] = (byte) (outBuff >> 16); + destination[destOffset + 1] = (byte) (outBuff >> 8); + destination[destOffset + 2] = (byte) (outBuff); + + return 3; + } catch (Exception e) { + System.out.println("" + source[srcOffset] + ": " + (DECODABET[source[srcOffset]])); + System.out.println("" + source[srcOffset + 1] + ": " + (DECODABET[source[srcOffset + 1]])); + System.out.println("" + source[srcOffset + 2] + ": " + (DECODABET[source[srcOffset + 2]])); + System.out.println("" + source[srcOffset + 3] + ": " + (DECODABET[source[srcOffset + 3]])); + return -1; + } // e nd catch + } + } // end decodeToBytes + + /** + * Very low-level access to decoding ASCII characters in the form of a byte array. Does not support automatically + * gunzipping or any other "fancy" features. + * + * @param source The Base64 encoded data + * @param off The offset of where to begin decoding + * @param len The length of characters to decode + * @return decoded data + * @since 1.3 + */ + public static byte[] decode(byte[] source, int off, int len) { + int len34 = len * 3 / 4; + byte[] outBuff = new byte[len34]; // Upper limit on size of output + int outBuffPosn = 0; + + byte[] b4 = new byte[4]; + int b4Posn = 0; + int i = 0; + byte sbiCrop = 0; + byte sbiDecode = 0; + for (i = off; i < off + len; i++) { + sbiCrop = (byte) (source[i] & 0x7f); // Only the low seven bits + sbiDecode = DECODABET[sbiCrop]; + + if (sbiDecode >= WHITE_SPACE_ENC) // White space, Equals sign or better + { + if (sbiDecode >= EQUALS_SIGN_ENC) { + b4[b4Posn++] = sbiCrop; + if (b4Posn > 3) { + outBuffPosn += decode4to3(b4, 0, outBuff, outBuffPosn); + b4Posn = 0; + + // If that was the equals sign, break out of 'for' loop + if (sbiCrop == EQUALS_SIGN) + break; + } // end if: quartet built + + } // end if: equals sign or better + + } // end if: white space, equals sign or better + else { + System.err.println("Bad Base64 input character at " + i + ": " + source[i] + "(decimal)"); + return null; + } // end else: + } // each input character + + byte[] out = new byte[outBuffPosn]; + System.arraycopy(outBuff, 0, out, 0, outBuffPosn); + return out; + } // end decode + + /** + * Decodes data from Base64 notation, automatically detecting gzip-compressed data and decompressing it. + * + * @param s the string to decode + * @return the decoded data + * @since 1.4 + */ + public static byte[] decode(String s) { + byte[] bytes; + try { + bytes = s.getBytes(PREFERRED_ENCODING); + } // end try + catch (java.io.UnsupportedEncodingException uee) { + bytes = s.getBytes(); + } // end catch + // + + // Decode + bytes = decode(bytes, 0, bytes.length); + + // Check to see if it's gzip-compressed + // GZIP Magic Two-Byte Number: 0x8b1f (35615) + if (bytes != null && bytes.length >= 4) { + + int head = ((int) bytes[0] & 0xff) | ((bytes[1] << 8) & 0xff00); + if (java.util.zip.GZIPInputStream.GZIP_MAGIC == head) { + java.io.ByteArrayInputStream bais = null; + java.util.zip.GZIPInputStream gzis = null; + java.io.ByteArrayOutputStream baos = null; + byte[] buffer = new byte[2048]; + int length = 0; + + try { + baos = new java.io.ByteArrayOutputStream(); + bais = new java.io.ByteArrayInputStream(bytes); + gzis = new java.util.zip.GZIPInputStream(bais); + + while ((length = gzis.read(buffer)) >= 0) { + baos.write(buffer, 0, length); + } // end while: reading input + + // No error? Get new bytes. + bytes = baos.toByteArray(); + + } // end try + catch (java.io.IOException e) { + // Just return originally-decoded bytes + } // end catch + finally { + try { + baos.close(); + } catch (Exception e) { + } + try { + gzis.close(); + } catch (Exception e) { + } + try { + bais.close(); + } catch (Exception e) { + } + } // end finally + + } // end if: gzipped + } // end if: bytes.length >= 2 + + return bytes; + } // end decode + + /** + * Attempts to decode Base64 data and deserialize a Java Object within. Returns null if there was an + * error. + * + * @param encodedObject The Base64 data to decode + * @return The decoded and deserialized object + * @since 1.5 + */ + public static Object decodeToObject(String encodedObject) { + // Decode and gunzip if necessary + byte[] objBytes = decode(encodedObject); + + java.io.ByteArrayInputStream bais = null; + java.io.ObjectInputStream ois = null; + Object obj = null; + + try { + bais = new java.io.ByteArrayInputStream(objBytes); + ois = new java.io.ObjectInputStream(bais); + + obj = ois.readObject(); + } // end try + catch (java.io.IOException e) { + e.printStackTrace(); + obj = null; + } // end catch + catch (java.lang.ClassNotFoundException e) { + e.printStackTrace(); + obj = null; + } // end catch + finally { + try { + bais.close(); + } catch (Exception e) { + } + try { + ois.close(); + } catch (Exception e) { + } + } // end finally + + return obj; + } // end decodeObject + + /** + * Convenience method for encoding data to a file. + * + * @param dataToEncode byte array of data to encode in base64 form + * @param filename Filename for saving encoded data + * @return true if successful, false otherwise + * + * @since 2.1 + */ + public static boolean encodeToFile(byte[] dataToEncode, String filename) { + boolean success = false; + Base64.OutputStream bos = null; + try { + bos = new Base64.OutputStream(new java.io.FileOutputStream(filename), Base64.ENCODE); + bos.write(dataToEncode); + success = true; + } // end try + catch (java.io.IOException e) { + + success = false; + } // end catch: IOException + finally { + try { + bos.close(); + } catch (Exception e) { + } + } // end finally + + return success; + } // end encodeToFile + + /** + * Convenience method for decoding data to a file. + * + * @param dataToDecode Base64-encoded data as a string + * @param filename Filename for saving decoded data + * @return true if successful, false otherwise + * + * @since 2.1 + */ + public static boolean decodeToFile(String dataToDecode, String filename) { + boolean success = false; + Base64.OutputStream bos = null; + try { + bos = new Base64.OutputStream(new java.io.FileOutputStream(filename), Base64.DECODE); + bos.write(dataToDecode.getBytes(PREFERRED_ENCODING)); + success = true; + } // end try + catch (java.io.IOException e) { + success = false; + } // end catch: IOException + finally { + try { + bos.close(); + } catch (Exception e) { + } + } // end finally + + return success; + } // end decodeToFile + + /** + * Convenience method for reading a base64-encoded file and decoding it. + * + * @param filename Filename for reading encoded data + * @return decoded byte array or null if unsuccessful + * + * @since 2.1 + */ + public static byte[] decodeFromFile(String filename) { + byte[] decodedData = null; + Base64.InputStream bis = null; + try { + // Set up some useful variables + java.io.File file = new java.io.File(filename); + byte[] buffer = null; + int length = 0; + int numBytes = 0; + + // Check for size of file + if (file.length() > Integer.MAX_VALUE) { + System.err.println("File is too big for this convenience method (" + file.length() + " bytes)."); + return null; + } // end if: file too big for int index + buffer = new byte[(int) file.length()]; + + // Open a stream + bis = new Base64.InputStream(new java.io.BufferedInputStream(new java.io.FileInputStream(file)), + Base64.DECODE); + + // Read until done + while ((numBytes = bis.read(buffer, length, 4096)) >= 0) + length += numBytes; + + // Save in a variable to return + decodedData = new byte[length]; + System.arraycopy(buffer, 0, decodedData, 0, length); + + } // end try + catch (java.io.IOException e) { + System.err.println("Error decoding from file " + filename); + } // end catch: IOException + finally { + try { + bis.close(); + } catch (Exception e) { + } + } // end finally + + return decodedData; + } // end decodeFromFile + + /** + * Convenience method for reading a binary file and base64-encoding it. + * + * @param filename Filename for reading binary data + * @return base64-encoded string or null if unsuccessful + * + * @since 2.1 + */ + public static String encodeFromFile(String filename) { + String encodedData = null; + Base64.InputStream bis = null; + try { + // Set up some useful variables + java.io.File file = new java.io.File(filename); + byte[] buffer = new byte[(int) (file.length() * 1.4)]; + int length = 0; + int numBytes = 0; + + // Open a stream + bis = new Base64.InputStream(new java.io.BufferedInputStream(new java.io.FileInputStream(file)), + Base64.ENCODE); + + // Read until done + while ((numBytes = bis.read(buffer, length, 4096)) >= 0) + length += numBytes; + + // Save in a variable to return + encodedData = new String(buffer, 0, length, Base64.PREFERRED_ENCODING); + + } // end try + catch (java.io.IOException e) { + System.err.println("Error encoding from file " + filename); + } // end catch: IOException + finally { + try { + bis.close(); + } catch (Exception e) { + } + } // end finally + + return encodedData; + } // end encodeFromFile + + /* ******** I N N E R C L A S S I N P U T S T R E A M ******** */ + + /** + * A {@link Base64.InputStream} will read data from another java.io.InputStream, given in the + * constructor, and encode/decode to/from Base64 notation on the fly. + * + * @see Base64 + * @since 1.3 + */ + public static class InputStream extends java.io.FilterInputStream { + private boolean encode; // Encoding or decoding + + private int position; // Current position in the buffer + + private byte[] buffer; // Small buffer holding converted data + + private int bufferLength; // Length of buffer (3 or 4) + + private int numSigBytes; // Number of meaningful bytes in the buffer + + private int lineLength; + + private boolean breakLines; // Break lines at less than 80 characters + + /** + * Constructs a {@link Base64.InputStream} in DECODE mode. + * + * @param in the java.io.InputStream from which to read data. + * @since 1.3 + */ + public InputStream(java.io.InputStream in) { + this(in, DECODE); + } // end constructor + + /** + * Constructs a {@link Base64.InputStream} in either ENCODE or DECODE mode. + *

+ * Valid options: + * + *

+         *       ENCODE or DECODE: Encode or Decode as data is read.
+         *       DONT_BREAK_LINES: don't break lines at 76 characters
+         *         (only meaningful when encoding)
+         *         <i>Note: Technically, this makes your encoding non-compliant.</i>
+         * 
+ * + *

+ * Example: new Base64.InputStream( in, Base64.DECODE ) + * + * + * @param in the java.io.InputStream from which to read data. + * @param options Specified options + * @see Base64#ENCODE + * @see Base64#DECODE + * @see Base64#DONT_BREAK_LINES + * @since 2.0 + */ + public InputStream(java.io.InputStream in, int options) { + super(in); + this.breakLines = (options & DONT_BREAK_LINES) != DONT_BREAK_LINES; + this.encode = (options & ENCODE) == ENCODE; + this.bufferLength = encode ? 4 : 3; + this.buffer = new byte[bufferLength]; + this.position = -1; + this.lineLength = 0; + } // end constructor + + /** + * Reads enough of the input stream to convert to/from Base64 and returns the next byte. + * + * @return next byte + * @since 1.3 + */ + public int read() throws java.io.IOException { + // Do we need to get data? + if (position < 0) { + if (encode) { + byte[] b3 = new byte[3]; + int numBinaryBytes = 0; + for (int i = 0; i < 3; i++) { + try { + int b = in.read(); + + // If end of stream, b is -1. + if (b >= 0) { + b3[i] = (byte) b; + numBinaryBytes++; + } // end if: not end of stream + + } // end try: read + catch (java.io.IOException e) { + // Only a problem if we got no data at all. + if (i == 0) + throw e; + + } // end catch + } // end for: each needed input byte + + if (numBinaryBytes > 0) { + encode3to4(b3, 0, numBinaryBytes, buffer, 0); + position = 0; + numSigBytes = 4; + } // end if: got data + else { + return -1; + } // end else + } // end if: encoding + + // Else decoding + else { + byte[] b4 = new byte[4]; + int i = 0; + for (i = 0; i < 4; i++) { + // Read four "meaningful" bytes: + int b = 0; + do { + b = in.read(); + } while (b >= 0 && DECODABET[b & 0x7f] <= WHITE_SPACE_ENC); + + if (b < 0) + break; // Reads a -1 if end of stream + + b4[i] = (byte) b; + } // end for: each needed input byte + + if (i == 4) { + numSigBytes = decode4to3(b4, 0, buffer, 0); + position = 0; + } // end if: got four characters + else if (i == 0) { + return -1; + } // end else if: also padded correctly + else { + // Must have broken out from above. + throw new java.io.IOException("Improperly padded Base64 input."); + } // end + + } // end else: decode + } // end else: get data + + // Got data? + if (position >= 0) { + // End of relevant data? + if ( /* !encode && */position >= numSigBytes) + return -1; + + if (encode && breakLines && lineLength >= MAX_LINE_LENGTH) { + lineLength = 0; + return '\n'; + } // end if + else { + lineLength++; // This isn't important when decoding + // but throwing an extra "if" seems + // just as wasteful. + + int b = buffer[position++]; + + if (position >= bufferLength) + position = -1; + + return b & 0xFF; // This is how you "cast" a byte that's + // intended to be unsigned. + } // end else + } // end if: position >= 0 + + // Else error + else { + // When JDK1.4 is more accepted, use an assertion here. + throw new java.io.IOException("Error in Base64 code reading stream."); + } // end else + } // end read + + /** + * Calls {@link #read()} repeatedly until the end of stream is reached or len bytes are read. + * Returns number of bytes read into array or -1 if end of stream is encountered. + * + * @param dest array to hold values + * @param off offset for array + * @param len max number of bytes to read into array + * @return bytes read into array or -1 if end of stream is encountered. + * @since 1.3 + */ + public int read(byte[] dest, int off, int len) throws java.io.IOException { + int i; + int b; + for (i = 0; i < len; i++) { + b = read(); + + // if( b < 0 && i == 0 ) + // return -1; + + if (b >= 0) + dest[off + i] = (byte) b; + else if (i == 0) + return -1; + else + break; // Out of 'for' loop + } // end for: each byte read + return i; + } // end read + + } // end inner class InputStream + + /* ******** I N N E R C L A S S O U T P U T S T R E A M ******** */ + + /** + * A {@link Base64.OutputStream} will write data to another java.io.OutputStream, given in the + * constructor, and encode/decode to/from Base64 notation on the fly. + * + * @see Base64 + * @since 1.3 + */ + public static class OutputStream extends java.io.FilterOutputStream { + private boolean encode; + + private int position; + + private byte[] buffer; + + private int bufferLength; + + private int lineLength; + + private boolean breakLines; + + private byte[] b4; // Scratch used in a few places + + private boolean suspendEncoding; + + /** + * Constructs a {@link Base64.OutputStream} in ENCODE mode. + * + * @param out the java.io.OutputStream to which data will be written. + * @since 1.3 + */ + public OutputStream(java.io.OutputStream out) { + this(out, ENCODE); + } // end constructor + + /** + * Constructs a {@link Base64.OutputStream} in either ENCODE or DECODE mode. + *

+ * Valid options: + * + *

+         *       ENCODE or DECODE: Encode or Decode as data is read.
+         *       DONT_BREAK_LINES: don't break lines at 76 characters
+         *         (only meaningful when encoding)
+         *         <i>Note: Technically, this makes your encoding non-compliant.</i>
+         * 
+ * + *

+ * Example: new Base64.OutputStream( out, Base64.ENCODE ) + * + * @param out the java.io.OutputStream to which data will be written. + * @param options Specified options. + * @see Base64#ENCODE + * @see Base64#DECODE + * @see Base64#DONT_BREAK_LINES + * @since 1.3 + */ + public OutputStream(java.io.OutputStream out, int options) { + super(out); + this.breakLines = (options & DONT_BREAK_LINES) != DONT_BREAK_LINES; + this.encode = (options & ENCODE) == ENCODE; + this.bufferLength = encode ? 3 : 4; + this.buffer = new byte[bufferLength]; + this.position = 0; + this.lineLength = 0; + this.suspendEncoding = false; + this.b4 = new byte[4]; + } // end constructor + + /** + * Writes the byte to the output stream after converting to/from Base64 notation. When encoding, bytes are + * buffered three at a time before the output stream actually gets a write() call. When decoding, bytes are + * buffered four at a time. + * + * @param theByte the byte to write + * @since 1.3 + */ + public void write(int theByte) throws java.io.IOException { + // Encoding suspended? + if (suspendEncoding) { + super.out.write(theByte); + return; + } // end if: supsended + + // Encode? + if (encode) { + buffer[position++] = (byte) theByte; + if (position >= bufferLength) { + out.write(encode3to4(b4, buffer, bufferLength)); + + lineLength += 4; + if (breakLines && lineLength >= MAX_LINE_LENGTH) { + out.write(NEW_LINE); + lineLength = 0; + } // end if: end of line + + position = 0; + } // end if: enough to output + } + + // Else, Decoding + else { + // Meaningful Base64 character? + if (DECODABET[theByte & 0x7f] > WHITE_SPACE_ENC) { + buffer[position++] = (byte) theByte; + if (position >= bufferLength) { + int len = Base64.decode4to3(buffer, 0, b4, 0); + out.write(b4, 0, len); + // out.write( Base64.decode4to3( buffer ) ); + position = 0; + } // end if: enough to output + } // end if: meaningful base64 character + else if (DECODABET[theByte & 0x7f] != WHITE_SPACE_ENC) { + throw new java.io.IOException("Invalid character in Base64 data."); + } // end else: not white space either + } // end else: decoding + } // end write + + /** + * Calls {@link #write(int)} repeatedly until len bytes are written. + * + * @param theBytes array from which to read bytes + * @param off offset for array + * @param len max number of bytes to read into array + * @since 1.3 + */ + public void write(byte[] theBytes, int off, int len) throws java.io.IOException { + // Encoding suspended? + if (suspendEncoding) { + super.out.write(theBytes, off, len); + return; + } // end if: supsended + + for (int i = 0; i < len; i++) { + write(theBytes[off + i]); + } // end for: each byte written + + } // end write + + /** + * Method added by PHIL. [Thanks, PHIL. -Rob] This pads the buffer without closing the stream. + */ + public void flushBase64() throws java.io.IOException { + if (position > 0) { + if (encode) { + out.write(encode3to4(b4, buffer, position)); + position = 0; + } // end if: encoding + else { + throw new java.io.IOException("Base64 input not properly padded."); + } // end else: decoding + } // end if: buffer partially full + + } // end flush + + /** + * Flushes and closes (I think, in the superclass) the stream. + * + * @since 1.3 + */ + public void close() throws java.io.IOException { + // 1. Ensure that pending characters are written + flushBase64(); + + // 2. Actually close the stream + // Base class both flushes and closes. + super.close(); + + buffer = null; + out = null; + } // end close + + /** + * Suspends encoding of the stream. May be helpful if you need to embed a piece of base640-encoded data in a + * stream. + * + * @since 1.5.1 + */ + public void suspendEncoding() throws java.io.IOException { + flushBase64(); + this.suspendEncoding = true; + } // end suspendEncoding + + /** + * Resumes encoding of the stream. May be helpful if you need to embed a piece of base640-encoded data in a + * stream. + * + * @since 1.5.1 + */ + public void resumeEncoding() { + this.suspendEncoding = false; + } // end resumeEncoding + + } // end inner class OutputStream + +} // end class Base64 Index: 3rdParty_sources/xmltooling/org/opensaml/xml/util/ClassIndexedSet.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/util/ClassIndexedSet.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/util/ClassIndexedSet.java 17 Aug 2012 15:17:17 -0000 1.1 @@ -0,0 +1,222 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.util; + +import java.util.AbstractSet; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +/** + * Set implementation which provides indexed access to set members via their class, + * and which allows only one instance of a given class to be present in the set. Null + * members are not allowed. + * + * @param the type of object stored by this class + */ +public class ClassIndexedSet extends AbstractSet implements Set { + + /** Storage for set members. */ + private HashSet set; + + /** Storage for index of class -> member. */ + private HashMap, T> index; + + /** + * Constructor. + * + */ + public ClassIndexedSet() { + set = new HashSet(); + index = new HashMap, T>(); + } + + /** {@inheritDoc} */ + public boolean add(T o) { + return add(o, false); + } + + /** + * Add member to set, optionally replacing any existing instance of the + * same class. + * + * @param o the object to add + * @param replace flag indicating whether to replace an existing class type + * @return true if object was added + * @throws IllegalArgumentException if set already contained an instance of the object's class + * and replacement was specified as false + * @throws NullPointerException if the object to add was null + */ + @SuppressWarnings("unchecked") + public boolean add(T o, boolean replace) throws NullPointerException, IllegalArgumentException { + if (o == null) { + throw new NullPointerException("Null elements are not allowed"); + } + boolean replacing = false; + Class indexClass = getIndexClass(o); + T existing = get(indexClass); + if (existing != null) { + replacing = true; + if (replace) { + remove(existing); + } else { + throw new IllegalArgumentException("Set already contains a member of index class " + + indexClass.getName()); + } + } + index.put(indexClass, o); + set.add(o); + return replacing; + } + + /** {@inheritDoc} */ + public void clear() { + set.clear(); + index.clear(); + } + + /** {@inheritDoc} */ + @SuppressWarnings("unchecked") + public boolean remove(Object o) { + if (set.contains(o)) { + removeFromIndex((T) o); + set.remove(o); + return true; + } + return false; + } + + /** {@inheritDoc} */ + public Iterator iterator() { + return new ClassIndexedSetIterator(this, set.iterator()); + } + + /** {@inheritDoc} */ + public int size() { + return set.size(); + } + + /** + * Check whether set contains an instance of the specified class. + * + * @param clazz the class to check + * @return true if set contains an instance of the specified class, false otherwise + */ + public boolean contains(Class clazz) { + return get(clazz)!=null; + } + + /** + * Get the set element specified by the class parameter. + * @param generic parameter which eliminates need for casting by the caller + * @param clazz the class to whose instance is to be retrieved + * @return the element whose class is of the type specified, or null + * + */ + @SuppressWarnings("unchecked") + public X get(Class clazz) { + return (X) index.get(clazz); + } + + /** + * Get the index class of the specified object. Subclasses may override to use + * a class index other than the main runtime class of the object. + * + * @param o the object whose class index to determine + * @return the class index value associated with the object instance + */ + @SuppressWarnings("unchecked") + protected Class getIndexClass(Object o) { + return (Class) o.getClass(); + } + + /** + * Remove the specified object from the index. + * + * @param o the object to remove + */ + private void removeFromIndex(T o) { + index.remove(getIndexClass(o)); + } + + /** + * Iterator for set implementation {@link ClassIndexedSet}. + * + */ + protected class ClassIndexedSetIterator implements Iterator { + + /** The set instance over which this instance is an iterator. */ + private ClassIndexedSet set; + + /** The iterator for the owner's underlying storage. */ + private Iterator iterator; + + /** Flag which tracks whether next() has been called at least once. */ + private boolean nextCalled; + + /** Flag which tracks whether remove can currently be called. */ + private boolean removeStateValid;; + + /** The element most recently returned by next(), and the target for any subsequent + * remove() operation. */ + private T current; + + /** + * Constructor. + * + * @param parentSet the {@link ClassIndexedSet} over which this instance is an iterator + * @param parentIterator the iterator for the parent's underlying storage + */ + protected ClassIndexedSetIterator(ClassIndexedSet parentSet, Iterator parentIterator) { + set = parentSet; + iterator = parentIterator; + current = null; + nextCalled = false; + removeStateValid = false; + } + + /** {@inheritDoc} */ + public boolean hasNext() { + return iterator.hasNext(); + } + + /** {@inheritDoc} */ + public T next() { + current = iterator.next(); + nextCalled = true; + removeStateValid = true; + return current; + } + + /** {@inheritDoc} */ + public void remove() { + if (! nextCalled) { + throw new IllegalStateException("remove() was called before calling next()"); + } + if (! removeStateValid) { + throw new IllegalStateException("remove() has already been called since the last call to next()"); + } + iterator.remove(); + set.removeFromIndex(current); + removeStateValid = false; + } + + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/util/DatatypeHelper.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/util/DatatypeHelper.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/util/DatatypeHelper.java 17 Aug 2012 15:17:17 -0000 1.1 @@ -0,0 +1,242 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.util; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.nio.charset.Charset; +import java.nio.charset.CharsetDecoder; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.StringTokenizer; + +/** Helper class for working with various datatypes. */ +public final class DatatypeHelper { + + /** Constructor. */ + private DatatypeHelper() { + + } + + /** + * A "safe" null/empty check for strings. + * + * @param s The string to check + * + * @return true if the string is null or the trimmed string is length zero + */ + public static boolean isEmpty(String s) { + if (s != null) { + String sTrimmed = s.trim(); + if (sTrimmed.length() > 0) { + return false; + } + } + + return true; + } + + /** + * Compares two strings for equality, allowing for nulls. + * + * @param type of object to compare + * @param s1 The first operand + * @param s2 The second operand + * + * @return true if both are null or both are non-null and the same strng value + */ + public static boolean safeEquals(T s1, T s2) { + if (s1 == null || s2 == null) { + return s1 == s2; + } + + return s1.equals(s2); + } + + /** + * A safe string trim that handles nulls. + * + * @param s the string to trim + * + * @return the trimmed string or null if the given string was null + */ + public static String safeTrim(String s) { + if (s != null) { + return s.trim(); + } + + return null; + } + + /** + * Removes preceeding or proceeding whitespace from a string or return null if the string is null or of zero length + * after trimming (i.e. if the string only contained whitespace). + * + * @param s the string to trim + * + * @return the trimmed string or null + */ + public static String safeTrimOrNullString(String s) { + if (s != null) { + String sTrimmed = s.trim(); + if (sTrimmed.length() > 0) { + return sTrimmed; + } + } + + return null; + } + + /** + * Converts an integer into an unsigned 4-byte array. + * + * @param integer integer to convert + * + * @return 4-byte array representing integer + */ + public static byte[] intToByteArray(int integer) { + byte[] intBytes = new byte[4]; + intBytes[0] = (byte) ((integer & 0xff000000) >>> 24); + intBytes[1] = (byte) ((integer & 0x00ff0000) >>> 16); + intBytes[2] = (byte) ((integer & 0x0000ff00) >>> 8); + intBytes[3] = (byte) ((integer & 0x000000ff)); + + return intBytes; + } + + /** + * Reads the contents of a file in to a byte array. + * + * @param file file to read + * @return the byte contents of the file + * + * @throws IOException throw if there is a problem reading the file in to the byte array + */ + public static byte[] fileToByteArray(File file) throws IOException { + long numOfBytes = file.length(); + + if (numOfBytes > Integer.MAX_VALUE) { + throw new IOException("File is to large to be read in to a byte array"); + } + + byte[] bytes = new byte[(int) numOfBytes]; + FileInputStream ins = new FileInputStream(file); + int offset = 0; + int numRead = 0; + do { + numRead = ins.read(bytes, offset, bytes.length - offset); + offset += numRead; + } while (offset < bytes.length && numRead >= 0); + + if (offset < bytes.length) { + throw new IOException("Could not completely read file " + file.getName()); + } + + ins.close(); + return bytes; + } + + /** + * Reads an input stream into a string. The provide stream is not closed. + * + * @param input the input stream to read + * @param decoder character decoder to use, if null, system default character set is used + * + * @return the string read from the stream + * + * @throws IOException thrown if there is a problem reading from the stream and decoding it + */ + public static String inputstreamToString(InputStream input, CharsetDecoder decoder) throws IOException { + CharsetDecoder charsetDecoder = decoder; + if (decoder == null) { + charsetDecoder = Charset.defaultCharset().newDecoder(); + } + + BufferedReader reader = new BufferedReader(new InputStreamReader(input, charsetDecoder)); + + StringBuilder stringBuffer = new StringBuilder(); + String line = reader.readLine(); + while(line != null){ + stringBuffer.append(line).append("\n"); + line = reader.readLine(); + } + + reader.close(); + + return stringBuffer.toString(); + } + + /** + * Converts a delimited string into a list. + * + * @param string the string to be split into a list + * @param delimiter the delimiter between values. This string may contain + * multiple delimiter characters, as allowed by + * {@link StringTokenizer} + * + * @return the list of values or an empty list if the given string is null or empty + */ + public static List stringToList(String string, String delimiter) { + if (delimiter == null) { + throw new IllegalArgumentException("String delimiter may not be null"); + } + + ArrayList values = new ArrayList(); + + String trimmedString = safeTrimOrNullString(string); + if (trimmedString != null) { + StringTokenizer tokens = new StringTokenizer(trimmedString, delimiter); + while (tokens.hasMoreTokens()) { + values.add(tokens.nextToken()); + } + } + + return values; + } + + /** + * Converts a List of strings into a single string, with values separated by a + * specified delimiter. + * + * @param values list of strings + * @param delimiter the delimiter used between values + * + * @return delimited string of values + */ + public static String listToStringValue(List values, String delimiter) { + if (delimiter == null) { + throw new IllegalArgumentException("String delimiter may not be null"); + } + + StringBuilder stringValue = new StringBuilder(); + Iterator valueItr = values.iterator(); + while(valueItr.hasNext()){ + stringValue.append(valueItr.next()); + if(valueItr.hasNext()){ + stringValue.append(delimiter); + } + } + + return stringValue.toString(); + } +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/util/IDIndex.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/util/IDIndex.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/util/IDIndex.java 17 Aug 2012 15:17:17 -0000 1.1 @@ -0,0 +1,162 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.util; + +import java.util.Collections; +import java.util.Map; +import java.util.Set; + +import net.jcip.annotations.NotThreadSafe; + +import org.opensaml.xml.XMLObject; + +/** + * Class which provides storage for the ID-to-XMLObject index mapping on an owning {@link org.opensaml.xml.XMLObject}. + */ +@NotThreadSafe +public class IDIndex { + + /** The XMLObject which owns this ID index. */ + private XMLObject owner; + + /** Mapping of ID attributes to XMLObjects in the subtree rooted at this object's owner. + * This allows constant-time dereferencing of ID-typed attributes within the subtree. */ + private Map idMappings; + + /** + * Constructor. + * + * @param newOwner the XMLObject which owns this ID-to-XMLObject index + * + * @throws NullPointerException thrown if the given XMLObject is null + */ + public IDIndex(XMLObject newOwner) throws NullPointerException { + if (newOwner == null) { + throw new NullPointerException("Attribute owner XMLObject may not be null"); + } + + owner = newOwner; + idMappings = new LazyMap(); + } + + + /** + * Register an ID-to-XMLObject mapping for one of this object's owner's children. + * + * @param id the XMLObject child's ID attribute value + * @param referent the XMLObject child + */ + public void registerIDMapping(String id, XMLObject referent) { + if (id == null) { + return; + } + + idMappings.put(id, referent); + if (owner.hasParent()) { + owner.getParent().getIDIndex().registerIDMapping(id, referent); + } + } + + /** + * Register multiple ID-to-XMLObject mappings for this object's owner's children. + * + * @param idIndex the ID-to-XMLObject mapping to register + */ + public void registerIDMappings(IDIndex idIndex) { + if (idIndex == null || idIndex.isEmpty()) { + return; + } + + idMappings.putAll(idIndex.getIDMappings()); + if (owner.hasParent()) { + owner.getParent().getIDIndex().registerIDMappings(idIndex); + } + } + + /** + * Deregister an ID-to-XMLObject mapping for one of this object's owner's children. + * + * @param id the ID attribute value of the XMLObject child to deregister + */ + public void deregisterIDMapping(String id) { + if (id == null) { + return; + } + + idMappings.remove(id); + if (owner.hasParent()) { + owner.getParent().getIDIndex().deregisterIDMapping(id); + } + } + + /** + * Deregister multiple ID-to-XMLObject mappings for this object's owner's children. + * + * @param idIndex the ID-to-XMLObject mappings to deregister + */ + public void deregisterIDMappings(IDIndex idIndex) { + if (idIndex == null || idIndex.isEmpty()) { + return; + } + + for (String id : idIndex.getIDs()) { + idMappings.remove(id); + } + if (owner.hasParent()) { + owner.getParent().getIDIndex().deregisterIDMappings(idIndex); + } + } + + /** + * Lookup and return the XMLObject identified by the specified ID attribute. + * + * @param id the ID attribute value to lookup + * @return the XMLObject identified by the ID attribute value + */ + public XMLObject lookup(String id) { + return idMappings.get(id); + } + + /** + * Return whether the index is currently empty. + * + * @return true if the index is currently empty + */ + public boolean isEmpty() { + return idMappings.isEmpty(); + } + + /** + * Get the set of ID strings which are the index keys. + * + * @return the set of ID strings which are keys to the index + */ + public Set getIDs() { + return Collections.unmodifiableSet(idMappings.keySet()); + } + + /** + * Get the ID-to-XMLObject mappings for this object's object's owner's children. + * + * @return the ID-to-XMLObject mapping + */ + protected Map getIDMappings() { + return Collections.unmodifiableMap(idMappings); + } + +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/util/IPAddressHelper.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/util/IPAddressHelper.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/util/IPAddressHelper.java 17 Aug 2012 15:17:17 -0000 1.1 @@ -0,0 +1,185 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.util; + +import java.net.InetAddress; +import java.net.UnknownHostException; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** Helper class for working with IP address data. */ +public final class IPAddressHelper { + + /** Constructor. */ + private IPAddressHelper() { + + } + + /** + * Convert the byte array representation of an IP address into a string. Supports IPv4 and IPv6 addresses. + * Supports optional subnet mask stored within the same byte array. If the latter is present, + * output will be: "ipAddr/mask". + * + * @param address IP address in byte array form (in network byte order) + * @return IP address as a string, or null if can not be processed + */ + public static String addressToString(byte[] address) { + Logger log = getLogger(); + if (isIPv4(address)) { + return ipv4ToString(address); + } else if (isIPv6(address)) { + return ipv6ToString(address); + } else { + log.error("IP address byte array was an invalid length: {}", address.length); + return null; + } + } + + /** + * Convert the byte array representation of an IPv4 address into a string. + * Supports optional subnet mask stored within the same byte array. If the latter is present, + * output will be: "ipAddr/mask". + * + * @param address IP address in byte array form (in network byte order) + * @return IP address as a string, or null if can not be processed + */ + private static String ipv4ToString(byte[] address) { + Logger log = getLogger(); + // This code was modeled after similar code in Sun's sun.security.x509.IPAddressName, + // used by sun.security.x509.X509CertImpl. + StringBuilder builder = new StringBuilder(); + byte[] ip = new byte[4]; + System.arraycopy(address, 0, ip, 0, 4); + try { + builder.append(InetAddress.getByAddress(ip).getHostAddress()); + } catch (UnknownHostException e) { + // Thrown if address is illegal length. + // Can't happen, we know that address is the right length. + log.error("Unknown host exception processing IP address byte array: {}", e.getMessage()); + return null; + } + + if(hasMask(address)) { + byte[] mask = new byte[4]; + System.arraycopy(address, 4, mask, 0, 4); + builder.append("/"); + try { + builder.append(InetAddress.getByAddress(mask).getHostAddress()); + } catch (UnknownHostException e) { + // Thrown if address is illegal length. + // Can't happen, we know that address is the right length. + log.error("Unknown host exception processing IP address byte array: {}", e.getMessage()); + return null; + } + } + return builder.toString(); + } + + /** + * Convert the byte array representation of an IPv6 address into a string. + * Supports optional subnet mask stored within the same byte array. If the latter is present, + * output will be: "ipAddr/mask". + * + * @param address IP address in byte array form (in network byte order) + * @return IP address as a string, or null if can not be processed + */ + private static String ipv6ToString(byte[] address) { + Logger log = getLogger(); + // This code was modeled after similar code in Sun's sun.security.x509.IPAddressName, + // used by sun.security.x509.X509CertImpl. + StringBuilder builder = new StringBuilder(); + byte[] ip = new byte[16]; + System.arraycopy(address, 0, ip, 0, 16); + try { + builder.append(InetAddress.getByAddress(ip).getHostAddress()); + } catch (UnknownHostException e) { + // Thrown if address is illegal length. + // Can't happen, we know that address is the right length. + log.error("Unknown host exception processing IP address byte array: {}", e.getMessage()); + return null; + } + + if(hasMask(address)) { + log.error("IPv6 subnet masks are currently unsupported"); + return null; + /* + byte[] mask = new byte[16]; + for(int i = 16; i < 32; i++) { + mask[i - 16] = address[i]; + } + + // TODO need to process bitmask array + // to determine and validate subnet mask + BitArray bitarray = new BitArray(128, mask); + int j; + for (j = 0; j < 128 && bitarray.get(j); j++); + builder.append("/"); + builder.append(j).toString(); + for (; j < 128; j++) { + if (bitarray.get(j)) { + log.error("Invalid IPv6 subdomain: set bit " + j + " not contiguous"); + return null; + } + } + */ + } + return builder.toString(); + } + + + /** + * Check whether IP address array is IPv4. + * + * @param address IP address byte array + * @return true if IPv4, false otherwise + */ + public static boolean isIPv4(byte[] address) { + return address.length == 4 || address.length == 8; + } + + /** + * Check whether IP address array is IPv6. + * + * @param address IP address byte array + * @return true if IPv6, false otherwise + */ + public static boolean isIPv6(byte[] address) { + return address.length == 16 || address.length == 32; + } + + /** + * Check whether IP address array has a subnet mask or not. + * + * @param address IP address byte array + * @return true if has subnet mask, false otherwise + */ + public static boolean hasMask(byte[] address) { + return address.length == 8 || address.length == 32; + } + + /** + * Get an SLF4J Logger. + * + * @return a Logger instance + */ + private static Logger getLogger() { + return LoggerFactory.getLogger(IPAddressHelper.class); + } + +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/util/IndexedXMLObjectChildrenList.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/util/IndexedXMLObjectChildrenList.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/util/IndexedXMLObjectChildrenList.java 17 Aug 2012 15:17:17 -0000 1.1 @@ -0,0 +1,375 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.util; + +import java.util.AbstractList; +import java.util.Collection; +import java.util.List; +import java.util.Map; + +import javax.xml.namespace.QName; + +import net.jcip.annotations.NotThreadSafe; + +import org.opensaml.xml.XMLObject; + +/** + * A list which indexes XMLObjects by their schema type and element QName for quick retrival based on those items. + * + * @param the type of element added to the list + */ +@NotThreadSafe +public class IndexedXMLObjectChildrenList extends XMLObjectChildrenList { + + /** Index of objects by type and name. */ + private Map> objectIndex; + + /** + * Constructor. + * + * @param parent the parent of the {@link XMLObject}s added to the list + */ + public IndexedXMLObjectChildrenList(XMLObject parent) { + super(parent); + objectIndex = new LazyMap>(); + } + + /** + * Constructor. + * + * @param parent the parent of all elements + * @param col collection to add to this list + */ + public IndexedXMLObjectChildrenList(XMLObject parent, Collection col) { + super(parent); + objectIndex = new LazyMap>(); + addAll(col); + } + + /** + * Inserts the specified element at the specified position in this list. Shifts the element currently at that + * position (if any) and any subsequent elements to the right (adds one to their indices). + * + * @param index index of element to add + * @param element element to be stored at the specified position + */ + public void add(int index, ElementType element) { + super.add(index, element); + indexElement(element); + } + + /** {@inheritDoc} */ + public void clear() { + super.clear(); + objectIndex.clear(); + } + + /** + * Retrieves all the SAMLObjects that have given schema type or element name. + * + * @param typeOrName the schema type or element name + * + * @return list of SAMLObjects that have given schema type or element name, which may be empty. + * Will not be null. + */ + public List get(QName typeOrName) { + checkAndCreateIndex(typeOrName); + return objectIndex.get(typeOrName); + } + + /** + * Check for the existence of an index for the specified QName and create it + * if it doesn't exist. + * + * @param index the index to check + */ + protected void checkAndCreateIndex(QName index) { + if (!objectIndex.containsKey(index)) { + objectIndex.put(index, new LazyList()); + } + } + + /** + * Indexes the given SAMLObject by type and element name. + * + * @param element the SAMLObject to index + */ + protected void indexElement(ElementType element) { + if (element == null) { + return; + } + + QName type = element.getSchemaType(); + if (type != null) { + indexElement(type, element); + } + + indexElement(element.getElementQName(), element); + } + + /** + * Indexes the given SAMLobject by the given index. + * + * @param index the index for the element + * @param element the element to be indexed + */ + protected void indexElement(QName index, ElementType element) { + List objects = get(index); + objects.add(element); + } + + /** + * Removes a given element from the list and index. + * + * @param element the element to be removed + * + * @return true if the element was in the list and removed, false if not + */ + public boolean remove(ElementType element) { + boolean elementRemoved = false; + + elementRemoved = super.remove(element); + if (elementRemoved) { + removeElementFromIndex(element); + } + + return elementRemoved; + } + + /** + * Removes the element at the specified position in this list. Shifts any subsequent elements to the left (subtracts + * one from their indices). Returns the element that was removed from the list + * + * @param index the index of the element to remove + * + * @return the element removed from the list + */ + public ElementType remove(int index) { + ElementType returnValue = super.remove(index); + + removeElementFromIndex(returnValue); + + return returnValue; + } + + /** + * Removes the given element from the schema type and element qname index. + * + * @param element the element to remove from the index + */ + protected void removeElementFromIndex(ElementType element) { + if (element == null) { + return; + } + + QName type = element.getSchemaType(); + if (type != null) { + removeElementFromIndex(type, element); + } + + removeElementFromIndex(element.getElementQName(), element); + } + + /** + * Removes an object from the given index id. + * + * @param index the id of the index + * @param element the element to be removed from that index + */ + protected void removeElementFromIndex(QName index, ElementType element) { + List objects = get(index); + objects.remove(element); + } + + /** + * Replaces the element at the specified position in this list with the specified element. + * + * @param index index of element to replace + * @param element element to be stored at the specified position + * + * @return the element previously at the specified position + */ + public ElementType set(int index, ElementType element) { + ElementType returnValue = super.set(index, element); + + removeElementFromIndex(returnValue); + + indexElement(element); + return returnValue; + } + + /** + * Returns a view of the list that only contains elements stored under the given index. The returned list is backed + * by this list so and supports all optional operations, so changes made to the returned list are reflected in this + * list. + * + * @param index index of the elements returned in the list view + * + * @return a view of this list that contains only the elements stored under the given index + */ + public List subList(QName index) { + checkAndCreateIndex(index); + return new ListView(this, index); + } +} + +/** + * A special list that works as a view of an IndexedXMLObjectChildrenList showing only the sublist associated with a + * given index. Operations performed on this sublist are reflected in the backing list. Index-based mutation operations + * are not supported. + * + * @param the XMLObject type that this list operates on + */ +class ListView extends AbstractList { + + /** List that backs this view. */ + private IndexedXMLObjectChildrenList backingList; + + /** Index that points to the list, in the backing list, that this view operates on. */ + private QName index; + + /** List, in the backing list, that the given index points to. */ + private List indexList; + + /** + * Constructor. + * + * @param newBackingList the list that backs this view + * @param newIndex the element schema type or name of the sublist this view operates on + */ + public ListView(IndexedXMLObjectChildrenList newBackingList, QName newIndex) { + backingList = newBackingList; + index = newIndex; + indexList = backingList.get(index); + } + + /** {@inheritDoc} */ + public boolean add(ElementType o) { + boolean result = backingList.add(o); + indexList = backingList.get(index); + return result; + } + + /** {@inheritDoc} */ + public void add(int newIndex, ElementType element) { + throw new UnsupportedOperationException(); + } + + /** {@inheritDoc} */ + public boolean addAll(Collection c) { + boolean result = backingList.addAll(c); + indexList = backingList.get(index); + return result; + } + + /** {@inheritDoc} */ + public boolean addAll(int index, Collection c) { + throw new UnsupportedOperationException(); + } + + /** {@inheritDoc} */ + public void clear() { + // Create a copy of the current list to avoid a potential concurrent modification error. + LazyList copy = new LazyList(); + copy.addAll(indexList); + backingList.removeAll(copy); + indexList = backingList.get(index); + } + + /** + * Checks to see if the given element is contained in this list. + * + * @param element the element to check for + * + * @return true if the element is in this list, false if not + */ + public boolean contains(Object element) { + return indexList.contains(element); + } + + /** {@inheritDoc} */ + public boolean containsAll(Collection c) { + return indexList.containsAll(c); + } + + /** {@inheritDoc} */ + public ElementType get(int newIndex) { + return indexList.get(newIndex); + } + + /** {@inheritDoc} */ + public int indexOf(Object o) { + return indexList.indexOf(o); + } + + /** {@inheritDoc} */ + public boolean isEmpty() { + return indexList.isEmpty(); + } + + /** {@inheritDoc} */ + public int lastIndexOf(Object o) { + return indexList.lastIndexOf(o); + } + + /** {@inheritDoc} */ + public ElementType remove(int newIndex) { + throw new UnsupportedOperationException(); + } + + /** {@inheritDoc} */ + public boolean remove(Object o) { + boolean result = backingList.remove(o); + indexList = backingList.get(index); + return result; + } + + /** {@inheritDoc} */ + public boolean removeAll(Collection c) { + boolean result = backingList.removeAll(c); + indexList = backingList.get(index); + return result; + } + + /** {@inheritDoc} */ + public boolean retainAll(Collection c) { + boolean result = backingList.retainAll(c); + indexList = backingList.get(index); + return result; + } + + /** {@inheritDoc} */ + public ElementType set(int newIndex, ElementType element) { + throw new UnsupportedOperationException(); + } + + /** {@inheritDoc} */ + public int size() { + return indexList.size(); + } + + /** {@inheritDoc} */ + public Object[] toArray() { + return indexList.toArray(); + } + + /** {@inheritDoc} */ + public T[] toArray(T[] a) { + return indexList.toArray(a); + } +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/util/IndexingObjectStore.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/util/IndexingObjectStore.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/util/IndexingObjectStore.java 17 Aug 2012 15:17:17 -0000 1.1 @@ -0,0 +1,239 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.util; + +import java.util.Map; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; + +import net.jcip.annotations.ThreadSafe; + +/** + * This class is used to store instances of objects that may be created independently but are, in face, the same object. + * For example, {@link org.opensaml.xml.signature.KeyInfo}s contain keys, certs, and CRLs. Multiple unique instances of + * a KeyInfo may contain, and separately construct, the exact same cert. KeyInfo could, therefore, create a class-level + * instance of this object store and put certs within it. In this manner the cert is only sitting in memory once and + * each KeyInfo simply stores a reference (index) to stored object. + * + * This store uses basic reference counting to keep track of how many of the respective objects are pointing to an + * entry. Adding an object that already exists, as determined by the objects hashCode() method, simply + * increments the reference counter. Removing an object decrements the counter. Only when the counter reaches zero is + * the object actually freed for garbage collection. + * + * Note the instance of an object returned by {@link #get(String)} need not be the same object as + * stored via {@link #put(Object)}. However, their hash codes will be equal. Therefore this store should never be + * used to store objects that produce identical hash codes but are not functionally identical objects. + * + * @param type of object being stored + */ +@ThreadSafe +public class IndexingObjectStore { + + /** Read/Write lock used to control synchronization over the backing data store. */ + private ReadWriteLock rwLock; + + /** Backing object data store. */ + private Map objectStore; + + /** Constructor. */ + public IndexingObjectStore() { + rwLock = new ReentrantReadWriteLock(); + objectStore = new LazyMap(); + } + + /** Clears the object store. */ + public void clear() { + Lock writeLock = rwLock.writeLock(); + writeLock.lock(); + try { + objectStore.clear(); + } finally { + writeLock.unlock(); + } + + } + + /** + * Checks whether the store contains an object registered under the given index. + * + * @param index the index to check + * + * @return true if an object is associated with the given index, false if not + */ + public boolean contains(String index) { + Lock readLock = rwLock.readLock(); + readLock.lock(); + try { + return objectStore.containsKey(index); + } finally { + readLock.unlock(); + } + } + + /** + * Checks if the store is empty. + * + * @return true if the store is empty, false if not + */ + public boolean isEmpty() { + return objectStore.isEmpty(); + } + + /** + * Adds the given object to the store. Technically this method only adds the object if it does not already exist in + * the store. If it does this method simply increments the reference count of the object. + * + * @param object the object to add to the store, may be null + * + * @return the index that may be used to later retrieve the object or null if the object was null + */ + public String put(T object) { + if (object == null) { + return null; + } + + Lock writeLock = rwLock.writeLock(); + writeLock.lock(); + try { + String index = Integer.toString(object.hashCode()); + + StoredObjectWrapper objectWrapper = objectStore.get(index); + if (objectWrapper == null) { + objectWrapper = new StoredObjectWrapper(object); + objectStore.put(index, objectWrapper); + } + objectWrapper.incremementReferenceCount(); + + return index; + } finally { + writeLock.unlock(); + } + } + + /** + * Gets a registered object by its index. + * + * @param index the index of an object previously registered, may be null + * + * @return the registered object or null if no object is registered for that index + */ + public T get(String index) { + if (index == null) { + return null; + } + + Lock readLock = rwLock.readLock(); + readLock.lock(); + try { + StoredObjectWrapper objectWrapper = objectStore.get(index); + if (objectWrapper != null) { + return objectWrapper.getObject(); + } + + return null; + } finally { + readLock.unlock(); + } + } + + /** + * Removes the object associated with the given index. Technically this method decrements the reference counter to + * the object. If, after the decrement, the reference counter is zero then, and only then, is the object actually + * freed for garbage collection. + * + * @param index the index of the object, may be null + */ + public void remove(String index) { + if (index == null) { + return; + } + + Lock writeLock = rwLock.writeLock(); + writeLock.lock(); + try { + StoredObjectWrapper objectWrapper = objectStore.get(index); + if (objectWrapper != null) { + objectWrapper.decremementReferenceCount(); + if (objectWrapper.getReferenceCount() == 0) { + objectStore.remove(index); + } + } + } finally { + writeLock.unlock(); + } + } + + /** + * Gets the total number of unique items in the store. This number is unaffected by the reference count of the + * individual stored objects. + * + * @return number of items in the store + */ + public int size() { + return objectStore.size(); + } + + /** Wrapper class that keeps track of the reference count for a stored object. */ + private class StoredObjectWrapper { + + /** The stored object. */ + private T object; + + /** The object reference count. */ + private int referenceCount; + + /** + * Constructor. + * + * @param wrappedObject the object being wrapped + */ + public StoredObjectWrapper(T wrappedObject) { + object = wrappedObject; + referenceCount = 0; + } + + /** + * Gets the wrapped object. + * + * @return the wrapped object + */ + public T getObject() { + return object; + } + + /** + * Gets the current reference count. + * + * @return current reference count + */ + public int getReferenceCount() { + return referenceCount; + } + + /** Increments the current reference count by one. */ + public void incremementReferenceCount() { + referenceCount += 1; + } + + /** Decrements the current reference count by one. */ + public void decremementReferenceCount() { + referenceCount -= 1; + } + } +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/util/LazyList.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/util/LazyList.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/util/LazyList.java 17 Aug 2012 15:17:17 -0000 1.1 @@ -0,0 +1,212 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.util; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import java.util.ListIterator; + +import net.jcip.annotations.NotThreadSafe; + +/** + * A list that is lazy initialized. This list takes very little memory when storing zero or one item. + * + * @param type of elements within the list + */ +@NotThreadSafe +public class LazyList implements List, Serializable { + + /** Serial version UID. */ + private static final long serialVersionUID = -7741904523916701817L; + + /** Delegate list. */ + private List delegate = Collections.emptyList(); + + /** {@inheritDoc} */ + public boolean add(ElementType item) { + if (delegate.isEmpty()) { + delegate = Collections.singletonList(item); + return true; + } else { + delegate = buildList(); + return delegate.add(item); + } + } + + /** {@inheritDoc} */ + public void add(int index, ElementType element) { + delegate = buildList(); + delegate.add(index, element); + } + + /** {@inheritDoc} */ + public boolean addAll(Collection collection) { + delegate = buildList(); + return delegate.addAll(collection); + } + + /** {@inheritDoc} */ + public boolean addAll(int index, Collection collection) { + delegate = buildList(); + return delegate.addAll(index, collection); + } + + /** {@inheritDoc} */ + public void clear() { + delegate = Collections.emptyList(); + } + + /** {@inheritDoc} */ + public boolean contains(Object element) { + return delegate.contains(element); + } + + /** {@inheritDoc} */ + public boolean containsAll(Collection collections) { + return delegate.containsAll(collections); + } + + /** {@inheritDoc} */ + public ElementType get(int index) { + return delegate.get(index); + } + + /** {@inheritDoc} */ + public int indexOf(Object element) { + return delegate.indexOf(element); + } + + /** {@inheritDoc} */ + public boolean isEmpty() { + return delegate.isEmpty(); + } + + /** {@inheritDoc} */ + public Iterator iterator() { + delegate = buildList(); + return delegate.iterator(); + } + + /** {@inheritDoc} */ + public int lastIndexOf(Object element) { + return delegate.lastIndexOf(element); + } + + /** {@inheritDoc} */ + public ListIterator listIterator() { + delegate = buildList(); + return delegate.listIterator(); + } + + /** {@inheritDoc} */ + public ListIterator listIterator(int index) { + delegate = buildList(); + return delegate.listIterator(index); + } + + /** {@inheritDoc} */ + public boolean remove(Object element) { + delegate = buildList(); + return delegate.remove(element); + } + + /** {@inheritDoc} */ + public ElementType remove(int index) { + delegate = buildList(); + return delegate.remove(index); + } + + /** {@inheritDoc} */ + public boolean removeAll(Collection collection) { + delegate = buildList(); + return delegate.removeAll(collection); + } + + /** {@inheritDoc} */ + public boolean retainAll(Collection collection) { + delegate = buildList(); + return delegate.retainAll(collection); + } + + /** {@inheritDoc} */ + public ElementType set(int index, ElementType element) { + delegate = buildList(); + return delegate.set(index, element); + } + + /** {@inheritDoc} */ + public int size() { + return delegate.size(); + } + + /** {@inheritDoc} */ + public List subList(int fromIndex, int toIndex) { + delegate = buildList(); + return delegate.subList(fromIndex, toIndex); + } + + /** {@inheritDoc} */ + public Object[] toArray() { + return delegate.toArray(); + } + + /** {@inheritDoc} */ + public T[] toArray(T[] type) { + return delegate.toArray(type); + } + + /** + * Builds an appropriate delegate for this list. + * + * @return delegate for this list + */ + protected List buildList() { + if (delegate instanceof ArrayList) { + return delegate; + } + + return new ArrayList(delegate); + } + + /** {@inheritDoc} */ + public String toString() { + return delegate.toString(); + } + + /** {@inheritDoc} */ + public int hashCode() { + return delegate.hashCode(); + } + + /** {@inheritDoc} */ + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + + if (obj == null || this.getClass() != obj.getClass()) { + return false; + } + + return delegate.equals(((LazyList) obj).delegate); + } +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/util/LazyMap.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/util/LazyMap.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/util/LazyMap.java 17 Aug 2012 15:17:17 -0000 1.1 @@ -0,0 +1,150 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.util; + +import java.io.Serializable; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +import net.jcip.annotations.NotThreadSafe; + +/** + * A map that is lazy initialized. This map takes very little memory when storing zero or one item. + * + * @param the type of the map keys + * @param the type of the map values + */ +@NotThreadSafe +public class LazyMap implements Map, Serializable { + + /** Serial version UID. */ + private static final long serialVersionUID = 121425595164176639L; + + /** The delegate map. */ + private Map delegate = Collections.emptyMap(); + + /** {@inheritDoc} */ + public void clear() { + delegate = Collections.emptyMap(); + } + + /** {@inheritDoc} */ + public boolean containsKey(Object key) { + return delegate.containsKey(key); + } + + /** {@inheritDoc} */ + public boolean containsValue(Object value) { + return delegate.containsValue(value); + } + + /** {@inheritDoc} */ + public Set> entrySet() { + delegate = buildMap(); + return delegate.entrySet(); + } + + /** {@inheritDoc} */ + public ValueType get(Object key) { + return delegate.get(key); + } + + /** {@inheritDoc} */ + public boolean isEmpty() { + return delegate.isEmpty(); + } + + /** {@inheritDoc} */ + public Set keySet() { + delegate = buildMap(); + return delegate.keySet(); + } + + /** {@inheritDoc} */ + public ValueType put(KeyType key, ValueType value) { + if (delegate.isEmpty()) { + delegate = Collections.singletonMap(key, value); + return null; + } else { + delegate = buildMap(); + return delegate.put(key, value); + } + } + + /** {@inheritDoc} */ + public void putAll(Map t) { + delegate = buildMap(); + delegate.putAll(t); + } + + /** {@inheritDoc} */ + public ValueType remove(Object key) { + delegate = buildMap(); + return delegate.remove(key); + } + + /** {@inheritDoc} */ + public int size() { + return delegate.size(); + } + + /** {@inheritDoc} */ + public Collection values() { + delegate = buildMap(); + return delegate.values(); + } + + /** + * Builds an appropriate delegate map. + * + * @return the delegate map + */ + protected Map buildMap() { + if (delegate instanceof HashMap) { + return delegate; + } + + return new HashMap(delegate); + } + + /** {@inheritDoc} */ + public String toString() { + return delegate.toString(); + } + + /** {@inheritDoc} */ + public int hashCode() { + return delegate.hashCode(); + } + + /** {@inheritDoc} */ + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + + if (obj == null || this.getClass() != obj.getClass()) { + return false; + } + + return delegate.equals(((LazyMap) obj).delegate); + } +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/util/LazySet.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/util/LazySet.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/util/LazySet.java 17 Aug 2012 15:17:17 -0000 1.1 @@ -0,0 +1,154 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.util; + +import java.io.Serializable; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +import net.jcip.annotations.NotThreadSafe; + +/** + * A set that is lazy initialized. This set takes very little memory when storing zero or one item. + * + * @param type of the elements within the set + */ +@NotThreadSafe +public class LazySet implements Set, Serializable { + + /** Serial version UID. */ + private static final long serialVersionUID = -1596445680460115174L; + + /** The delegate set. */ + private Set delegate = Collections.emptySet(); + + /** {@inheritDoc} */ + public boolean add(ElementType element) { + if (delegate.isEmpty()) { + delegate = Collections.singleton(element); + return true; + } else { + delegate = createImplementation(); + return delegate.add(element); + } + } + + /** {@inheritDoc} */ + public boolean addAll(Collection collection) { + delegate = createImplementation(); + return delegate.addAll(collection); + } + + /** {@inheritDoc} */ + public void clear() { + delegate = Collections.emptySet(); + } + + /** {@inheritDoc} */ + public boolean contains(Object element) { + return delegate.contains(element); + } + + /** {@inheritDoc} */ + public boolean containsAll(Collection collection) { + return delegate.containsAll(collection); + } + + /** {@inheritDoc} */ + public boolean isEmpty() { + return delegate.isEmpty(); + } + + /** {@inheritDoc} */ + public Iterator iterator() { + delegate = createImplementation(); + return delegate.iterator(); + } + + /** {@inheritDoc} */ + public boolean remove(Object element) { + delegate = createImplementation(); + return delegate.remove(element); + } + + /** {@inheritDoc} */ + public boolean removeAll(Collection collection) { + delegate = createImplementation(); + return delegate.removeAll(collection); + } + + /** {@inheritDoc} */ + public boolean retainAll(Collection collection) { + delegate = createImplementation(); + return delegate.retainAll(collection); + } + + /** {@inheritDoc} */ + public int size() { + return delegate.size(); + } + + /** {@inheritDoc} */ + public Object[] toArray() { + return delegate.toArray(); + } + + /** {@inheritDoc} */ + public T[] toArray(T[] type) { + return delegate.toArray(type); + } + + /** + * Builds an appropriate delegate set. + * + * @return the delegate set + */ + private Set createImplementation() { + if (delegate instanceof HashSet) { + return delegate; + } + + return new HashSet(delegate); + } + + /** {@inheritDoc} */ + public String toString() { + return delegate.toString(); + } + + /** {@inheritDoc} */ + public int hashCode() { + return delegate.hashCode(); + } + + /** {@inheritDoc} */ + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + + if (obj == null || this.getClass() != obj.getClass()) { + return false; + } + + return delegate.equals(((LazySet) obj).delegate); + } +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/util/Pair.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/util/Pair.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/util/Pair.java 17 Aug 2012 15:17:17 -0000 1.1 @@ -0,0 +1,113 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.util; + +/** + * Container for a pair of objects. + * + * @param type of the first object in the pair + * @param type of the second object in the pair + */ +public class Pair { + + /** First object in pair. */ + private T1 first; + + /** Second object in pair. */ + private T2 second; + + /** + * Constructor. + * + * @param newFirst first object in the pair + * @param newSecond second object in the pair + */ + public Pair(T1 newFirst, T2 newSecond) { + first = newFirst; + second = newSecond; + } + + /** + * Gets the first object in the pair. + * + * @return first object in the pair + */ + public T1 getFirst() { + return first; + } + + /** + * Sets the first object in the pair. + * + * @param newFirst first object in the pair + */ + public void setFirst(T1 newFirst) { + first = newFirst; + } + + /** + * Gets the second object in the pair. + * + * @return second object in the pair + */ + public T2 getSecond() { + return second; + } + + /** + * Sets the second object in the pair. + * + * @param newSecond second object in the pair + */ + public void setSecond(T2 newSecond) { + second = newSecond; + } + + /** {@inheritDoc} */ + @SuppressWarnings("unchecked") + public boolean equals(Object o) { + if(o == this){ + return true; + } + + if (o instanceof Pair) { + Pair otherPair = (Pair) o; + return DatatypeHelper.safeEquals(getFirst(), otherPair.getFirst()) + && DatatypeHelper.safeEquals(getSecond(), otherPair.getSecond()); + } + + return false; + } + + /** {@inheritDoc} */ + public int hashCode() { + int result = 17; + if (first != null) { + result = 37 * result + first.hashCode(); + } + if (second != null) { + result = 37 * result + second.hashCode(); + } + return result; + } + + /** {@inheritDoc} */ + public String toString() { + return "(" + getFirst() + "," + getSecond() + ")"; + } +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/util/SingletonFactory.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/util/SingletonFactory.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/util/SingletonFactory.java 17 Aug 2012 15:17:16 -0000 1.1 @@ -0,0 +1,42 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.util; + +/** + * An interface for factory classes which implement a singleton pattern for producing an + * output class based on an input class. + * + *

+ * Classes which implement this interface should ensure that exactly one instance of a given output + * class is returned from the factory for a given instance of an input class. + *

+ * + * @param the factory input class type + * @param the factory output class type + */ +public interface SingletonFactory { + + /** + * Obtain an instance of the output class based on an input class instance. + * + * @param input the input class instance + * @return an output class instance + */ + public Output getInstance(Input input); + +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/util/ValueTypeIndexedMap.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/util/ValueTypeIndexedMap.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/util/ValueTypeIndexedMap.java 17 Aug 2012 15:17:16 -0000 1.1 @@ -0,0 +1,230 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.util; + +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +/** + * Map implementation which allows subsets of entries to be retrieved based on the type of the entry value. + * + * @param the type of object used as keys + * @param the type of object stored as values + */ +public class ValueTypeIndexedMap implements Map { + + /** Class to represent null values. */ + private static class NullValue {} + + /** Storage for index of class -> members. */ + private Map, Map> index; + + /** Storage for map members. */ + private Map map; + + /** Set of valid types for this map. */ + private Set types; + + /** Constructor. */ + public ValueTypeIndexedMap() { + this(new HashSet()); + } + + /** + * Constructor. + * + * @param newMap existing map to build from. + * @param newTypes collection of value types to index + */ + public ValueTypeIndexedMap(Map newMap, Collection newTypes) { + map = newMap; + types = new HashSet(newTypes); + index = new HashMap, Map>(); + rebuildIndex(); + } + + /** + * Constructor. + * + * @param newTypes collection of value types to index + */ + public ValueTypeIndexedMap(Collection newTypes) { + this(new HashMap(), newTypes); + } + + /** {@inheritDoc} */ + public void clear() { + map.clear(); + rebuildIndex(); + } + + /** {@inheritDoc} */ + public boolean containsKey(Object key) { + return map.containsKey(key); + } + + /** {@inheritDoc} */ + public boolean containsValue(Object value) { + return map.containsValue(value); + } + + /** {@inheritDoc} */ + public Set> entrySet() { + return map.entrySet(); + } + + /** {@inheritDoc} */ + public ValueType get(Object key) { + return map.get(key); + } + + /** + * Get the value types that are indexed. + * + * @return which value types are indexed + */ + public Set getTypes() { + return types; + } + + /** {@inheritDoc} */ + public boolean isEmpty() { + return map.isEmpty(); + } + + /** {@inheritDoc} */ + public Set keySet() { + return map.keySet(); + } + + /** + * Check if the object is of the specified type, taking null into account as well. + * + * @param type type to check for + * @param object object to check + * @return true if the object is of the specified type + */ + private Boolean matchType(Class type, Object object) { + return type.isInstance(object) || (type == NullValue.class && object == null); + } + + /** {@inheritDoc} */ + public ValueType put(KeyType key, ValueType value) { + ValueType oldValue = map.put(key, value); + + for (Class type : index.keySet()) { + if (type == null) { type = NullValue.class; } + if (matchType(type, value)) { + index.get(type).put(key, value); + } else if (matchType(type, oldValue)) { + index.get(type).remove(key); + } + } + + return oldValue; + } + + /** {@inheritDoc} */ + public void putAll(Map t) { + // this is probably not the most efficient way to do this + for (KeyType key : t.keySet()) { + put(key, t.get(key)); + } + } + + /** + * Rebuild internal index. + */ + public void rebuildIndex() { + index.clear(); + ValueType value; + + for (Class type : types) { + if (type == null) { type = NullValue.class; } + index.put(type, new HashMap()); + for (KeyType key : map.keySet()) { + value = map.get(key); + if (matchType(type, value)) { + index.get(type).put(key, value); + } + } + } + } + + /** {@inheritDoc} */ + public ValueType remove(Object key) { + ValueType value = map.remove(key); + + for (Class type : index.keySet()) { + if (type.isInstance(value)) { + index.get(type).remove(key); + } + } + + return value; + } + + /** + * Set which value types are indexed. + * + * @param newTypes which value types are indexed + */ + public void setTypes(Collection newTypes) { + this.types = new HashSet(newTypes); + } + + /** {@inheritDoc} */ + public int size() { + return map.size(); + } + + /** + * Returns an unmodifiable map of the entries whose value is of the specified type. + * + * @param type of values to include in the returned map + * @param type type of values to return + * @return sub map of entries whose value is of type SubType or null if the specified type is not a valid type for + * this map. + */ + @SuppressWarnings("unchecked") + public Map subMap(Class type) { + Class key = type; + if (key == null) { key = NullValue.class; } + if (index.containsKey(key)) { + return Collections.unmodifiableMap((Map) index.get(key)); + } else { + return Collections.emptyMap(); + } + } + + /** {@inheritDoc} */ + public String toString() { + return map.toString(); + } + + /** {@inheritDoc} */ + public Collection values() { + return map.values(); + } + + +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/util/XMLAttributeHelper.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/util/XMLAttributeHelper.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/util/XMLAttributeHelper.java 17 Aug 2012 15:17:17 -0000 1.1 @@ -0,0 +1,207 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.util; + +import org.opensaml.xml.AttributeExtensibleXMLObject; +import org.opensaml.xml.BaseBearing; +import org.opensaml.xml.IdBearing; +import org.opensaml.xml.LangBearing; +import org.opensaml.xml.SpaceBearing; +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.SpaceBearing.XMLSpaceEnum; + +/** + * Helper methods for working with global attributes from the XML namespace. These are namely: + *
    + *
  1. xml:id
  2. + *
  3. xml:lang
  4. + *
  5. xml:base
  6. + *
  7. xml:space
  8. + *
+ */ +public final class XMLAttributeHelper { + + /** + * Private constructor. + */ + private XMLAttributeHelper() { + } + + /** + * Adds a xml:id attribute to the given XML object. + * + * @param xmlObject the XML object to which to add the attribute + * @param id the Id value + */ + public static void addXMLId(XMLObject xmlObject, String id) { + if (xmlObject instanceof IdBearing) { + ((IdBearing)xmlObject).setXMLId(id); + } else if (xmlObject instanceof AttributeExtensibleXMLObject) { + ((AttributeExtensibleXMLObject)xmlObject).getUnknownAttributes() + .put(IdBearing.XML_ID_ATTR_NAME, id); + } else { + throw new IllegalArgumentException("Specified object was neither IdBearing nor AttributeExtensible"); + } + } + + /** + * Gets the xml:id attribute from a given XML object. + * + * @param xmlObject the XML object from which to extract the attribute + * + * @return the value of the xml:id attribute, or null if not present + */ + public static String getXMLId(XMLObject xmlObject) { + String value = null; + if (xmlObject instanceof IdBearing) { + value = DatatypeHelper.safeTrimOrNullString(((IdBearing)xmlObject).getXMLId()); + if (value != null) { + return value; + } + } + if (xmlObject instanceof AttributeExtensibleXMLObject) { + value = DatatypeHelper.safeTrimOrNullString(((AttributeExtensibleXMLObject)xmlObject) + .getUnknownAttributes().get(IdBearing.XML_ID_ATTR_NAME)); + return value; + } + return null; + } + + /** + * Adds a xml:lang attribute to the given XML object. + * + * @param xmlObject the XML object to which to add the attribute + * @param lang the lang value + */ + public static void addXMLLang(XMLObject xmlObject, String lang) { + if (xmlObject instanceof LangBearing) { + ((LangBearing)xmlObject).setXMLLang(lang); + } else if (xmlObject instanceof AttributeExtensibleXMLObject) { + ((AttributeExtensibleXMLObject)xmlObject).getUnknownAttributes() + .put(LangBearing.XML_LANG_ATTR_NAME, lang); + } else { + throw new IllegalArgumentException("Specified object was neither LangBearing nor AttributeExtensible"); + } + } + + /** + * Gets the xml:lang attribute from a given XML object. + * + * @param xmlObject the XML object from which to extract the attribute + * + * @return the value of the xml:lang attribute, or null if not present + */ + public static String getXMLLang(XMLObject xmlObject) { + String value = null; + if (xmlObject instanceof LangBearing) { + value = DatatypeHelper.safeTrimOrNullString(((LangBearing)xmlObject).getXMLLang()); + if (value != null) { + return value; + } + } + if (xmlObject instanceof AttributeExtensibleXMLObject) { + value = DatatypeHelper.safeTrimOrNullString(((AttributeExtensibleXMLObject)xmlObject) + .getUnknownAttributes().get(LangBearing.XML_LANG_ATTR_NAME)); + return value; + } + return null; + } + + /** + * Adds a xml:base attribute to the given XML object. + * + * @param xmlObject the XML object to which to add the attribute + * @param base the base value + */ + public static void addXMLBase(XMLObject xmlObject, String base) { + if (xmlObject instanceof BaseBearing) { + ((BaseBearing)xmlObject).setXMLBase(base); + } else if (xmlObject instanceof AttributeExtensibleXMLObject) { + ((AttributeExtensibleXMLObject)xmlObject).getUnknownAttributes() + .put(BaseBearing.XML_BASE_ATTR_NAME, base); + } else { + throw new IllegalArgumentException("Specified object was neither BaseBearing nor AttributeExtensible"); + } + } + + /** + * Gets the xml:base attribute from a given XML object. + * + * @param xmlObject the XML object from which to extract the attribute + * + * @return the value of the xml:base attribute, or null if not present + */ + public static String getXMLBase(XMLObject xmlObject) { + String value = null; + if (xmlObject instanceof BaseBearing) { + value = DatatypeHelper.safeTrimOrNullString(((BaseBearing)xmlObject).getXMLBase()); + if (value != null) { + return value; + } + } + if (xmlObject instanceof AttributeExtensibleXMLObject) { + value = DatatypeHelper.safeTrimOrNullString(((AttributeExtensibleXMLObject)xmlObject) + .getUnknownAttributes().get(BaseBearing.XML_BASE_ATTR_NAME)); + return value; + } + return null; + } + + /** + * Adds a xml:space attribute to the given XML object. + * + * @param xmlObject the XML object to which to add the attribute + * @param space the space value + */ + public static void addXMLSpace(XMLObject xmlObject, XMLSpaceEnum space) { + if (xmlObject instanceof SpaceBearing) { + ((SpaceBearing)xmlObject).setXMLSpace(space); + } else if (xmlObject instanceof AttributeExtensibleXMLObject) { + ((AttributeExtensibleXMLObject)xmlObject).getUnknownAttributes() + .put(SpaceBearing.XML_SPACE_ATTR_NAME, space.toString()); + } else { + throw new IllegalArgumentException("Specified object was neither SpaceBearing nor AttributeExtensible"); + } + } + + /** + * Gets the xml:space attribute from a given XML object. + * + * @param xmlObject the XML object from which to extract the attribute + * + * @return the value of the xml:space attribute, or null if not present + */ + public static XMLSpaceEnum getXMLSpace(XMLObject xmlObject) { + XMLSpaceEnum valueEnum = null; + if (xmlObject instanceof SpaceBearing) { + valueEnum = ((SpaceBearing)xmlObject).getXMLSpace(); + if (valueEnum != null) { + return valueEnum; + } + } + String valueString = null; + if (xmlObject instanceof AttributeExtensibleXMLObject) { + valueString = DatatypeHelper.safeTrimOrNullString(((AttributeExtensibleXMLObject)xmlObject) + .getUnknownAttributes().get(SpaceBearing.XML_SPACE_ATTR_NAME)); + if (valueString != null) { + return XMLSpaceEnum.parseValue(valueString); + } + } + return null; + } +} Index: 3rdParty_sources/xmltooling/org/opensaml/xml/util/XMLConstants.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/util/XMLConstants.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/util/XMLConstants.java 17 Aug 2012 15:17:17 -0000 1.1 @@ -0,0 +1,97 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.util; + +import javax.xml.namespace.QName; + +/** + * XML related constants. + */ +public class XMLConstants { + + // **************************** + // XML Tooling + // **************************** + /** Configuration namespace. */ + public static final String XMLTOOLING_CONFIG_NS = "http://www.opensaml.org/xmltooling-config"; + + /** Configuration namespace prefix. */ + public static final String XMLTOOLING_CONFIG_PREFIX = "xt"; + + /** Name of the object provider used for objects that don't have a registered object provider. */ + public static final String XMLTOOLING_DEFAULT_OBJECT_PROVIDER = "DEFAULT"; + + /** Location, on the classpath, of the XMLTooling configuration schema. */ + public static final String XMLTOOLING_SCHEMA_LOCATION = "/schema/xmltooling-config.xsd"; + + // **************************** + // Core XML + // **************************** + /** XML core namespace. */ + public static final String XML_NS = "http://www.w3.org/XML/1998/namespace"; + + /** XML core prefix for xml attributes. */ + public static final String XML_PREFIX = "xml"; + + /** XML namespace for xmlns attributes. */ + public static final String XMLNS_NS = "http://www.w3.org/2000/xmlns/"; + + /** XML namespace prefix for xmlns attributes. */ + public static final String XMLNS_PREFIX = "xmlns"; + + /** XML Schema namespace. */ + public static final String XSD_NS = "http://www.w3.org/2001/XMLSchema"; + + /** XML Schema QName prefix. */ + public static final String XSD_PREFIX = "xs"; + + /** XML Schema Instance namespace. */ + public static final String XSI_NS = "http://www.w3.org/2001/XMLSchema-instance"; + + /** XML Schema Instance QName prefix. */ + public static final String XSI_PREFIX = "xsi"; + + /** XML XMLSecSignatureImpl namespace. */ + public static final String XMLSIG_NS = "http://www.w3.org/2000/09/xmldsig#"; + + /** XML XMLSecSignatureImpl QName prefix. */ + public static final String XMLSIG_PREFIX = "ds"; + + /** XML Encryption namespace. */ + public static final String XMLENC_NS = "http://www.w3.org/2001/04/xmlenc#"; + + /** XML Encryption QName prefix. */ + public static final String XMLENC_PREFIX = "xenc"; + + /** XML Schema instance xsi:type attribute QName. */ + public static final QName XSI_TYPE_ATTRIB_NAME = + new QName(XSI_NS, "type", XSI_PREFIX); + + /** XML Schema instance xsi:type attribute QName. */ + public static final QName XSI_SCHEMA_LOCATION_ATTRIB_NAME = + new QName(XSI_NS, "schemaLocation", XSI_PREFIX); + + /** XML Schema instance xsi:type attribute QName. */ + public static final QName XSI_NO_NAMESPACE_SCHEMA_LOCATION_ATTRIB_NAME = + new QName(XSI_NS, "noNamespaceSchemaLocation", XSI_PREFIX); + + /** XML Schema instance xsi:type attribute QName. */ + public static final QName XSI_NIL_ATTRIB_NAME = + new QName(XSI_NS, "nil", XSI_PREFIX); + +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/util/XMLHelper.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/util/XMLHelper.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/util/XMLHelper.java 17 Aug 2012 15:17:17 -0000 1.1 @@ -0,0 +1,1208 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.util; + +import java.io.OutputStream; +import java.io.StringWriter; +import java.io.Writer; +import java.util.ArrayList; +import java.util.Collections; +import java.util.GregorianCalendar; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.StringTokenizer; +import java.util.Map.Entry; + +import javax.xml.datatype.DatatypeConfigurationException; +import javax.xml.datatype.DatatypeFactory; +import javax.xml.datatype.Duration; +import javax.xml.namespace.QName; + +import org.opensaml.xml.Configuration; +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.XMLRuntimeException; +import org.opensaml.xml.parse.XMLParserException; +import org.w3c.dom.Attr; +import org.w3c.dom.DOMConfiguration; +import org.w3c.dom.DOMImplementation; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.w3c.dom.Text; +import org.w3c.dom.ls.DOMImplementationLS; +import org.w3c.dom.ls.LSOutput; +import org.w3c.dom.ls.LSSerializer; +import org.w3c.dom.ls.LSSerializerFilter; + +/** + * A helper class for working with W3C DOM objects. + */ +public final class XMLHelper { + + /** + * A string which contains the valid delimiters for the XML Schema 'list' type. These are: space, newline, carriage + * return, and tab. + */ + public static final String LIST_DELIMITERS = " \n\r\t"; + + /** DOM configuration parameters used by LSSerializer in pretty print format output. */ + private static Map prettyPrintParams; + + /** JAXP DatatypeFactory. */ + private static DatatypeFactory dataTypeFactory; + + /** Constructor. */ + private XMLHelper() { + + } + + /** + * Gets a static instance of a JAXP DatatypeFactory. + * + * @return the factory or null if the factory could not be created + */ + public static DatatypeFactory getDataTypeFactory() { + if (dataTypeFactory == null) { + try { + dataTypeFactory = DatatypeFactory.newInstance(); + } catch (DatatypeConfigurationException e) { + // do nothing + } + } + + return dataTypeFactory; + } + + /** + * Checks if the given element has an xsi:type defined for it. + * + * @param e the DOM element + * + * @return true if there is a type, false if not + */ + public static boolean hasXSIType(Element e) { + if (e != null) { + if (e.getAttributeNodeNS(XMLConstants.XSI_NS, "type") != null) { + return true; + } + } + + return false; + } + + /** + * Gets the XSI type for a given element if it has one. + * + * @param e the element + * + * @return the type or null + */ + public static QName getXSIType(Element e) { + if (hasXSIType(e)) { + Attr attribute = e.getAttributeNodeNS(XMLConstants.XSI_NS, "type"); + String attributeValue = attribute.getTextContent().trim(); + StringTokenizer tokenizer = new StringTokenizer(attributeValue, ":"); + String prefix = null; + String localPart; + if (tokenizer.countTokens() > 1) { + prefix = tokenizer.nextToken(); + localPart = tokenizer.nextToken(); + } else { + localPart = tokenizer.nextToken(); + } + + return constructQName(e.lookupNamespaceURI(prefix), localPart, prefix); + } + + return null; + } + + /** + * Gets the ID attribute of a DOM element. + * + * @param domElement the DOM element + * + * @return the ID attribute or null if there isn't one + */ + public static Attr getIdAttribute(Element domElement) { + if (!domElement.hasAttributes()) { + return null; + } + + NamedNodeMap attributes = domElement.getAttributes(); + Attr attribute; + for (int i = 0; i < attributes.getLength(); i++) { + attribute = (Attr) attributes.item(i); + if (attribute.isId()) { + return attribute; + } + } + + return null; + } + + /** + * Gets the QName for the given DOM node. + * + * @param domNode the DOM node + * + * @return the QName for the element or null if the element was null + */ + public static QName getNodeQName(Node domNode) { + if (domNode != null) { + return constructQName(domNode.getNamespaceURI(), domNode.getLocalName(), domNode.getPrefix()); + } + + return null; + } + + /** + * Gets the lcoale currently active for the element. This is done by looking for an xml:lang attribute and parsing + * its content. If no xml:lang attribute is present the default locale is returned. This method only uses the + * language primary tag, as defined by RFC3066. + * + * @param element element to retrieve local information for + * + * @return the active local of the element + */ + public static Locale getLanguage(Element element) { + String lang = DatatypeHelper.safeTrimOrNullString(element.getAttributeNS(XMLConstants.XML_NS, "lang")); + if (lang != null) { + if (lang.contains("-")) { + lang = lang.substring(0, lang.indexOf("-")); + } + return new Locale(lang.toUpperCase()); + } else { + return Locale.getDefault(); + } + } + + /** + * Constructs an attribute owned by the given document with the given name. + * + * @param owningDocument the owning document + * @param attributeName the name of that attribute + * + * @return the constructed attribute + */ + public static Attr constructAttribute(Document owningDocument, QName attributeName) { + return constructAttribute(owningDocument, attributeName.getNamespaceURI(), attributeName.getLocalPart(), + attributeName.getPrefix()); + } + + /** + * Constructs an attribute owned by the given document with the given name. + * + * @param document the owning document + * @param namespaceURI the URI for the namespace the attribute is in + * @param localName the local name + * @param prefix the prefix of the namespace that attribute is in + * + * @return the constructed attribute + */ + public static Attr constructAttribute(Document document, String namespaceURI, String localName, String prefix) { + String trimmedLocalName = DatatypeHelper.safeTrimOrNullString(localName); + + if (trimmedLocalName == null) { + throw new IllegalArgumentException("Local name may not be null or empty"); + } + + String qualifiedName; + String trimmedPrefix = DatatypeHelper.safeTrimOrNullString(prefix); + if (trimmedPrefix != null) { + qualifiedName = trimmedPrefix + ":" + DatatypeHelper.safeTrimOrNullString(trimmedLocalName); + } else { + qualifiedName = DatatypeHelper.safeTrimOrNullString(trimmedLocalName); + } + + if (DatatypeHelper.isEmpty(namespaceURI)) { + return document.createAttributeNS(null, qualifiedName); + } else { + return document.createAttributeNS(namespaceURI, qualifiedName); + } + } + + /** + * Constructs a QName from an attributes value. + * + * @param attribute the attribute with a QName value + * + * @return a QName from an attributes value, or null if the given attribute is null + */ + public static QName getAttributeValueAsQName(Attr attribute) { + if (attribute == null || DatatypeHelper.isEmpty(attribute.getValue())) { + return null; + } + + String attributeValue = attribute.getTextContent(); + String[] valueComponents = attributeValue.split(":"); + if (valueComponents.length == 1) { + return constructQName(attribute.lookupNamespaceURI(null), valueComponents[0], null); + } else { + return constructQName(attribute.lookupNamespaceURI(valueComponents[0]), valueComponents[1], + valueComponents[0]); + } + } + + /** + * Parses the attribute's value. If the value is 0 or "false" then false is returned, if the value is 1 or "true" + * then true is returned, if the value is anything else then null returned. + * + * @param attribute attribute whose value will be converted to a boolean + * + * @return boolean value of the attribute or null + */ + public static Boolean getAttributeValueAsBoolean(Attr attribute) { + if (attribute == null) { + return null; + } + + String valueStr = attribute.getValue(); + if (valueStr.equals("0") || valueStr.equals("false")) { + return Boolean.FALSE; + } else if (valueStr.equals("1") || valueStr.equals("true")) { + return Boolean.TRUE; + } else { + return null; + } + } + + /** + * Gets the value of a list-type attribute as a list. + * + * @param attribute attribute whose value will be turned into a list + * + * @return list of values, never null + */ + public static List getAttributeValueAsList(Attr attribute) { + if (attribute == null) { + return Collections.emptyList(); + } + return DatatypeHelper.stringToList(attribute.getValue(), LIST_DELIMITERS); + } + + /** + * Marshall an attribute name and value to a DOM Element. This is particularly useful for attributes whose names + * appear in namespace-qualified form. + * + * @param attributeName the attribute name in QName form + * @param attributeValue the attribute value + * @param domElement the target element to which to marshall + * @param isIDAttribute flag indicating whether the attribute being marshalled should be handled as an ID-typed + * attribute + */ + public static void marshallAttribute(QName attributeName, String attributeValue, Element domElement, + boolean isIDAttribute) { + Document document = domElement.getOwnerDocument(); + Attr attribute = XMLHelper.constructAttribute(document, attributeName); + attribute.setValue(attributeValue); + domElement.setAttributeNodeNS(attribute); + if (isIDAttribute) { + domElement.setIdAttributeNode(attribute, true); + } + } + + /** + * Marshall an attribute name and value to a DOM Element. This is particularly useful for attributes whose names + * appear in namespace-qualified form. + * + * @param attributeName the attribute name in QName form + * @param attributeValues the attribute values + * @param domElement the target element to which to marshall + * @param isIDAttribute flag indicating whether the attribute being marshalled should be handled as an ID-typed + * attribute + */ + public static void marshallAttribute(QName attributeName, List attributeValues, Element domElement, + boolean isIDAttribute) { + marshallAttribute(attributeName, DatatypeHelper.listToStringValue(attributeValues, " "), domElement, + isIDAttribute); + } + + /** + * Marshall the attributes represented by the indicated AttributeMap into the indicated DOM Element. + * + * @param attributeMap the AttributeMap + * @param domElement the target Element + */ + public static void marshallAttributeMap(AttributeMap attributeMap, Element domElement) { + Document document = domElement.getOwnerDocument(); + Attr attribute = null; + for (Entry entry : attributeMap.entrySet()) { + attribute = XMLHelper.constructAttribute(document, entry.getKey()); + attribute.setValue(entry.getValue()); + domElement.setAttributeNodeNS(attribute); + if (Configuration.isIDAttribute(entry.getKey()) || attributeMap.isIDAttribute(entry.getKey())) { + domElement.setIdAttributeNode(attribute, true); + } + } + } + + /** + * Unmarshall a DOM Attr to an AttributeMap. + * + * @param attributeMap the target AttributeMap + * @param attribute the target DOM Attr + */ + public static void unmarshallToAttributeMap(AttributeMap attributeMap, Attr attribute) { + QName attribQName = XMLHelper.constructQName(attribute.getNamespaceURI(), attribute.getLocalName(), attribute + .getPrefix()); + attributeMap.put(attribQName, attribute.getValue()); + if (attribute.isId() || Configuration.isIDAttribute(attribQName)) { + attributeMap.registerID(attribQName); + } + } + + /** + * Constructs a QName from an element's adjacent Text child nodes. + * + * @param element the element with a QName value + * + * @return a QName from an element's value, or null if the given element is empty + */ + public static QName getElementContentAsQName(Element element) { + if (element == null) { + return null; + } + + String elementContent = null; + NodeList nodeList = element.getChildNodes(); + for (int i = 0; i < nodeList.getLength(); i++) { + Node node = nodeList.item(i); + if (node.getNodeType() == Node.TEXT_NODE) { + elementContent = DatatypeHelper.safeTrimOrNullString(((Text) node).getWholeText()); + break; + } + } + + if (elementContent == null) { + return null; + } + + String[] valueComponents = elementContent.split(":"); + if (valueComponents.length == 1) { + return constructQName(element.lookupNamespaceURI(null), valueComponents[0], null); + } else { + return constructQName(element.lookupNamespaceURI(valueComponents[0]), valueComponents[1], + valueComponents[0]); + } + } + + /** + * Gets the value of a list-type element as a list. + * + * @param element element whose value will be turned into a list + * + * @return list of values, never null + */ + public static List getElementContentAsList(Element element) { + if (element == null) { + return Collections.emptyList(); + } + return DatatypeHelper.stringToList(element.getTextContent(), LIST_DELIMITERS); + } + + /** + * Constructs a QName. + * + * @param namespaceURI the namespace of the QName + * @param localName the local name of the QName + * @param prefix the prefix of the QName, may be null + * + * @return the QName + */ + public static QName constructQName(String namespaceURI, String localName, String prefix) { + if (DatatypeHelper.isEmpty(prefix)) { + return new QName(namespaceURI, localName); + } else if (DatatypeHelper.isEmpty(namespaceURI)) { + return new QName(localName); + } + + return new QName(namespaceURI, localName, prefix); + } + + /** + * Constructs a QName from a string (attribute or element content) value. + * + * @param qname the QName string + * @param owningObject XMLObject, with cached DOM, owning the QName + * + * @return the QName respresented by the string + */ + public static QName constructQName(String qname, XMLObject owningObject) { + return constructQName(qname, owningObject.getDOM()); + } + + /** + * Constructs a QName from a string (attribute element content) value. + * + * @param qname the QName string + * @param owningElement parent DOM element of the Node which contains the QName value + * + * @return the QName respresented by the string + */ + public static QName constructQName(String qname, Element owningElement) { + String nsURI; + String nsPrefix; + String name; + + if (qname.indexOf(":") > -1) { + StringTokenizer qnameTokens = new StringTokenizer(qname, ":"); + nsPrefix = qnameTokens.nextToken(); + name = qnameTokens.nextToken(); + } else { + nsPrefix = ""; + name = qname; + } + + nsURI = lookupNamespaceURI(owningElement, nsPrefix); + return constructQName(nsURI, name, nsPrefix); + } + + /** + * Constructs an element, rooted in the given document, with the given name. + * + * @param document the document containing the element + * @param elementName the name of the element, must contain a local name, may contain a namespace URI and prefix + * + * @return the element + */ + public static Element constructElement(Document document, QName elementName) { + return constructElement(document, elementName.getNamespaceURI(), elementName.getLocalPart(), elementName + .getPrefix()); + } + + /** + * Constructs an element, rooted in the given document, with the given information. + * + * @param document the document containing the element + * @param namespaceURI the URI of the namespace the element is in + * @param localName the element's local name + * @param prefix the prefix of the namespace the element is in + * + * @return the element + */ + public static Element constructElement(Document document, String namespaceURI, String localName, String prefix) { + String trimmedLocalName = DatatypeHelper.safeTrimOrNullString(localName); + + if (trimmedLocalName == null) { + throw new IllegalArgumentException("Local name may not be null or empty"); + } + + String qualifiedName; + String trimmedPrefix = DatatypeHelper.safeTrimOrNullString(prefix); + if (trimmedPrefix != null) { + qualifiedName = trimmedPrefix + ":" + DatatypeHelper.safeTrimOrNullString(trimmedLocalName); + } else { + qualifiedName = DatatypeHelper.safeTrimOrNullString(trimmedLocalName); + } + + if (!DatatypeHelper.isEmpty(namespaceURI)) { + return document.createElementNS(namespaceURI, qualifiedName); + } else { + return document.createElementNS(null, qualifiedName); + } + } + + /** + * Appends the child Element to the parent Element, adopting the child Element into the parent's Document if needed. + * + * @param parentElement the parent Element + * @param childElement the child Element + */ + public static void appendChildElement(Element parentElement, Element childElement) { + Document parentDocument = parentElement.getOwnerDocument(); + adoptElement(childElement, parentDocument); + + parentElement.appendChild(childElement); + } + + /** + * Adopts an element into a document if the child is not already in the document. + * + * @param adoptee the element to be adopted + * @param adopter the document into which the element is adopted + */ + public static void adoptElement(Element adoptee, Document adopter) { + if (!(adoptee.getOwnerDocument().equals(adopter))) { + if (adopter.adoptNode(adoptee) == null) { + // This can happen if the adopter and adoptee were produced by different DOM implementations + throw new XMLRuntimeException("DOM Element node adoption failed"); + } + } + } + + /** + * Creates a text node with the given content and appends it as child to the given element. + * + * @param domElement the element to recieve the text node + * @param textContent the content for the text node + */ + public static void appendTextContent(Element domElement, String textContent) { + if (textContent == null) { + return; + } + Document parentDocument = domElement.getOwnerDocument(); + Text textNode = parentDocument.createTextNode(textContent); + domElement.appendChild(textNode); + } + + /** + * Adds a namespace declaration (xmlns:) attribute to the given element. + * + * @param domElement the element to add the attribute to + * @param namespaceURI the URI of the namespace + * @param prefix the prefix for the namespace + */ + public static void appendNamespaceDeclaration(Element domElement, String namespaceURI, String prefix) { + String nsURI = DatatypeHelper.safeTrimOrNullString(namespaceURI); + String nsPrefix = DatatypeHelper.safeTrimOrNullString(prefix); + + String attributeName; + if (nsPrefix == null) { + attributeName = XMLConstants.XMLNS_PREFIX; + } else { + attributeName = XMLConstants.XMLNS_PREFIX + ":" + nsPrefix; + } + + String attributeValue; + if (nsURI == null) { + attributeValue = ""; + } else { + attributeValue = nsURI; + } + + domElement.setAttributeNS(XMLConstants.XMLNS_NS, attributeName, attributeValue); + } + + /** + * Looks up the namespace URI associated with the given prefix starting at the given element. This method differs + * from the {@link Node#lookupNamespaceURI(java.lang.String)} in that it only those namespaces declared by an xmlns + * attribute are inspected. The Node method also checks the namespace a particular node was created in by way of a + * call like {@link Document#createElementNS(java.lang.String, java.lang.String)} even if the resulting element + * doesn't have an namespace delcaration attribute. + * + * @param startingElement the starting element + * @param prefix the prefix to look up + * + * @return the namespace URI for the given prefix + */ + public static String lookupNamespaceURI(Element startingElement, String prefix) { + return lookupNamespaceURI(startingElement, null, prefix); + } + + /** + * Looks up the namespace URI associated with the given prefix starting at the given element. This method differs + * from the {@link Node#lookupNamespaceURI(java.lang.String)} in that it only those namespaces declared by an xmlns + * attribute are inspected. The Node method also checks the namespace a particular node was created in by way of a + * call like {@link Document#createElementNS(java.lang.String, java.lang.String)} even if the resulting element + * doesn't have an namespace delcaration attribute. + * + * @param startingElement the starting element + * @param stopingElement the ancestor of the starting element that serves as the upper-bound, inclusive, for the + * search + * @param prefix the prefix to look up + * + * @return the namespace URI for the given prefer or null + */ + public static String lookupNamespaceURI(Element startingElement, Element stopingElement, String prefix) { + String namespaceURI; + + // This code is a modified version of the lookup code within Xerces + if (startingElement.hasAttributes()) { + NamedNodeMap map = startingElement.getAttributes(); + int length = map.getLength(); + for (int i = 0; i < length; i++) { + Node attr = map.item(i); + String attrPrefix = attr.getPrefix(); + String value = attr.getNodeValue(); + namespaceURI = attr.getNamespaceURI(); + if (namespaceURI != null && namespaceURI.equals(XMLConstants.XMLNS_NS)) { + // at this point we are dealing with DOM Level 2 nodes only + if (prefix == null && attr.getNodeName().equals(XMLConstants.XMLNS_PREFIX)) { + // default namespace + return value; + } else if (attrPrefix != null && attrPrefix.equals(XMLConstants.XMLNS_PREFIX) + && attr.getLocalName().equals(prefix)) { + // non default namespace + return value; + } + } + } + } + + if (startingElement != stopingElement) { + Element ancestor = getElementAncestor(startingElement); + if (ancestor != null) { + return lookupNamespaceURI(ancestor, stopingElement, prefix); + } + } + + return null; + } + + /** + * Looks up the namespace prefix associated with the given URI starting at the given element. This method differs + * from the {@link Node#lookupPrefix(java.lang.String)} in that it only those namespaces declared by an xmlns + * attribute are inspected. The Node method also checks the namespace a particular node was created in by way of a + * call like {@link Document#createElementNS(java.lang.String, java.lang.String)} even if the resulting element + * doesn't have an namespace delcaration attribute. + * + * @param startingElement the starting element + * @param namespaceURI the uri to look up + * + * @return the prefix for the given namespace URI + */ + public static String lookupPrefix(Element startingElement, String namespaceURI) { + return lookupPrefix(startingElement, null, namespaceURI); + } + + /** + * Looks up the namespace prefix associated with the given URI starting at the given element. This method differs + * from the {@link Node#lookupPrefix(java.lang.String)} in that it only those namespaces declared by an xmlns + * attribute are inspected. The Node method also checks the namespace a particular node was created in by way of a + * call like {@link Document#createElementNS(java.lang.String, java.lang.String)} even if the resulting element + * doesn't have an namespace delcaration attribute. + * + * @param startingElement the starting element + * @param stopingElement the ancestor of the starting element that serves as the upper-bound, inclusive, for the + * search + * @param namespaceURI the uri to look up + * + * @return the prefix for the given namespace URI + */ + public static String lookupPrefix(Element startingElement, Element stopingElement, String namespaceURI) { + String namespace; + + // This code is a modified version of the lookup code within Xerces + if (startingElement.hasAttributes()) { + NamedNodeMap map = startingElement.getAttributes(); + int length = map.getLength(); + for (int i = 0; i < length; i++) { + Node attr = map.item(i); + String attrPrefix = attr.getPrefix(); + String value = attr.getNodeValue(); + namespace = attr.getNamespaceURI(); + if (namespace != null && namespace.equals(XMLConstants.XMLNS_NS)) { + // DOM Level 2 nodes + if (attr.getNodeName().equals(XMLConstants.XMLNS_PREFIX) + || (attrPrefix != null && attrPrefix.equals(XMLConstants.XMLNS_PREFIX)) + && value.equals(namespaceURI)) { + + String localname = attr.getLocalName(); + String foundNamespace = startingElement.lookupNamespaceURI(localname); + if (foundNamespace != null && foundNamespace.equals(namespaceURI)) { + return localname; + } + } + + } + } + } + + if (startingElement != stopingElement) { + Element ancestor = getElementAncestor(startingElement); + if (ancestor != null) { + return lookupPrefix(ancestor, stopingElement, namespaceURI); + } + } + + return null; + } + + /** + * Gets the child nodes with the given namespace qualified tag name. If you need to retrieve multiple, named, + * children consider using {@link #getChildElements(Element)}. + * + * @param root element to retrieve the children from + * @param namespaceURI namespace URI of the child element + * @param localName local, tag, name of the child element + * + * @return list of child elements, never null + */ + public static List getChildElementsByTagNameNS(Element root, String namespaceURI, String localName) { + ArrayList children = new ArrayList(); + NodeList childNodes = root.getChildNodes(); + + int numOfNodes = childNodes.getLength(); + Node childNode; + Element e; + for (int i = 0; i < numOfNodes; i++) { + childNode = childNodes.item(i); + if (childNode.getNodeType() == Node.ELEMENT_NODE) { + e = (Element) childNode; + if (DatatypeHelper.safeEquals(e.getNamespaceURI(), namespaceURI) + && DatatypeHelper.safeEquals(e.getLocalName(), localName)) { + children.add(e); + } + } + } + + return children; + } + + /** + * Gets the child nodes with the given local tag name. If you need to retrieve multiple, named, children consider + * using {@link #getChildElements(Element)}. + * + * @param root element to retrieve the children from + * @param localName local, tag, name of the child element + * + * @return list of child elements, never null + */ + public static List getChildElementsByTagName(Element root, String localName) { + ArrayList children = new ArrayList(); + NodeList childNodes = root.getChildNodes(); + + int numOfNodes = childNodes.getLength(); + Node childNode; + Element e; + for (int i = 0; i < numOfNodes; i++) { + childNode = childNodes.item(i); + if (childNode.getNodeType() == Node.ELEMENT_NODE) { + e = (Element) childNode; + if (DatatypeHelper.safeEquals(e.getLocalName(), localName)) { + children.add(e); + } + } + } + + return children; + } + + /** + * Gets the child elements of the given element in a single iteration. + * + * @param root element to get the child elements of + * + * @return child elements indexed by namespace qualifed tag name, never null + */ + public static Map> getChildElements(Element root) { + Map> children = new HashMap>(); + NodeList childNodes = root.getChildNodes(); + + int numOfNodes = childNodes.getLength(); + Node childNode; + Element e; + QName qname; + List elements; + for (int i = 0; i < numOfNodes; i++) { + childNode = childNodes.item(i); + if (childNode.getNodeType() == Node.ELEMENT_NODE) { + e = (Element) childNode; + qname = getNodeQName(e); + elements = children.get(qname); + if (elements == null) { + elements = new ArrayList(); + children.put(qname, elements); + } + + elements.add(e); + } + } + + return children; + } + + /** + * Gets the ancestor element node to the given node. + * + * @param currentNode the node to retrive the ancestor for + * + * @return the ancestral element node of the current node, or null + */ + public static Element getElementAncestor(Node currentNode) { + Node parent = currentNode.getParentNode(); + if (parent != null) { + short type = parent.getNodeType(); + if (type == Node.ELEMENT_NODE) { + return (Element) parent; + } + return getElementAncestor(parent); + } + return null; + } + + /** + * Converts a Node into a String using the DOM, level 3, Load/Save serializer. + * + * @param node the node to be written to a string + * + * @return the string representation of the node + */ + public static String nodeToString(Node node) { + StringWriter writer = new StringWriter(); + writeNode(node, writer); + return writer.toString(); + } + + /** + * Pretty prints the XML node. + * + * @param node xml node to print + * + * @return pretty-printed xml + */ + public static String prettyPrintXML(Node node) { + StringWriter writer = new StringWriter(); + writeNode(node, writer, getPrettyPrintParams()); + return writer.toString(); + } + + /** + * Create the parameters set used in pretty print formatting of an LSSerializer. + * + * @return the params map + */ + private static Map getPrettyPrintParams() { + if (prettyPrintParams == null) { + prettyPrintParams = new LazyMap(); + prettyPrintParams.put("format-pretty-print", Boolean.TRUE); + } + return prettyPrintParams; + } + + /** + * Writes a Node out to a Writer using the DOM, level 3, Load/Save serializer. The written content is encoded using + * the encoding specified in the writer configuration. + * + * @param node the node to write out + * @param output the writer to write the XML to + */ + public static void writeNode(Node node, Writer output) { + writeNode(node, output, null); + } + + /** + * Writes a Node out to a Writer using the DOM, level 3, Load/Save serializer. The written content is encoded using + * the encoding specified in the writer configuration. + * + * @param node the node to write out + * @param output the writer to write the XML to + * @param serializerParams parameters to pass to the {@link DOMConfiguration} of the serializer + * instance, obtained via {@link LSSerializer#getDomConfig()}. May be null. + */ + public static void writeNode(Node node, Writer output, Map serializerParams) { + DOMImplementationLS domImplLS = getLSDOMImpl(node); + + LSSerializer serializer = getLSSerializer(domImplLS, serializerParams); + + LSOutput serializerOut = domImplLS.createLSOutput(); + serializerOut.setCharacterStream(output); + + serializer.write(node, serializerOut); + } + + /** + * Writes a Node out to an OutputStream using the DOM, level 3, Load/Save serializer. The written content + * is encoded using the encoding specified in the output stream configuration. + * + * @param node the node to write out + * @param output the output stream to write the XML to + */ + public static void writeNode(Node node, OutputStream output) { + writeNode(node, output, null); + } + + + /** + * Writes a Node out to an OutputStream using the DOM, level 3, Load/Save serializer. The written content + * is encoded using the encoding specified in the output stream configuration. + * + * @param node the node to write out + * @param output the output stream to write the XML to + * @param serializerParams parameters to pass to the {@link DOMConfiguration} of the serializer + * instance, obtained via {@link LSSerializer#getDomConfig()}. May be null. + */ + public static void writeNode(Node node, OutputStream output, Map serializerParams) { + DOMImplementationLS domImplLS = getLSDOMImpl(node); + + LSSerializer serializer = getLSSerializer(domImplLS, serializerParams); + + LSOutput serializerOut = domImplLS.createLSOutput(); + serializerOut.setByteStream(output); + + serializer.write(node, serializerOut); + } + + /** + * Obtain a the DOM, level 3, Load/Save serializer {@link LSSerializer} instance from the + * given {@link DOMImplementationLS} instance. + * + *

+ * The serializer instance will be configured with the parameters passed as the serializerParams + * argument. It will also be configured with an {@link LSSerializerFilter} that shows all nodes to the filter, + * and accepts all nodes shown. + *

+ * + * @param domImplLS the DOM Level 3 Load/Save implementation to use + * @param serializerParams parameters to pass to the {@link DOMConfiguration} of the serializer + * instance, obtained via {@link LSSerializer#getDomConfig()}. May be null. + * + * @return a new LSSerializer instance + */ + public static LSSerializer getLSSerializer(DOMImplementationLS domImplLS, Map serializerParams) { + LSSerializer serializer = domImplLS.createLSSerializer(); + + serializer.setFilter(new LSSerializerFilter() { + + public short acceptNode(Node arg0) { + return FILTER_ACCEPT; + } + + public int getWhatToShow() { + return SHOW_ALL; + } + }); + + + if (serializerParams != null) { + DOMConfiguration serializerDOMConfig = serializer.getDomConfig(); + for (String key : serializerParams.keySet()) { + serializerDOMConfig.setParameter(key, serializerParams.get(key)); + } + } + + return serializer; + } + + /** + * Get the DOM Level 3 Load/Save {@link DOMImplementationLS} for the given node. + * + * @param node the node to evaluate + * @return the DOMImplementationLS for the given node + */ + public static DOMImplementationLS getLSDOMImpl(Node node) { + DOMImplementation domImpl; + if (node instanceof Document) { + domImpl = ((Document) node).getImplementation(); + } else { + domImpl = node.getOwnerDocument().getImplementation(); + } + + DOMImplementationLS domImplLS = (DOMImplementationLS) domImpl.getFeature("LS", "3.0"); + return domImplLS; + } + + /** + * Converts a QName into a string that can be used for attribute values or element content. + * + * @param qname the QName to convert to a string + * + * @return the string value of the QName + */ + public static String qnameToContentString(QName qname) { + StringBuffer buf = new StringBuffer(); + + String prefix = DatatypeHelper.safeTrimOrNullString(qname.getPrefix()); + if (prefix != null) { + buf.append(prefix); + buf.append(":"); + } + buf.append(qname.getLocalPart()); + return buf.toString(); + } + + /** + * Ensures that all the visibly used namespaces referenced by the given Element or its descendants are declared by + * the given Element or one of its descendants. + * + * NOTE: This is a very costly operation. + * + * @param domElement the element to act as the root of the namespace declarations + * + * @throws XMLParserException thrown if a namespace prefix is encountered that can't be resolved to a namespace URI + */ + public static void rootNamespaces(Element domElement) throws XMLParserException { + rootNamespaces(domElement, domElement); + } + + /** + * Recursively called function that ensures all the visibly used namespaces referenced by the given Element or its + * descendants are declared if they don't appear in the list of already resolved namespaces. + * + * @param domElement the Element + * @param upperNamespaceSearchBound the "root" element of the fragment where namespaces may be rooted + * + * @throws XMLParserException thrown if a namespace prefix is encountered that can't be resolved to a namespace URI + */ + private static void rootNamespaces(Element domElement, Element upperNamespaceSearchBound) throws XMLParserException { + String namespaceURI = null; + String namespacePrefix = domElement.getPrefix(); + + // Check if the namespace for this element is already declared on this element + boolean nsDeclaredOnElement = false; + if (namespacePrefix == null) { + nsDeclaredOnElement = domElement.hasAttributeNS(null, XMLConstants.XMLNS_PREFIX); + } else { + nsDeclaredOnElement = domElement.hasAttributeNS(XMLConstants.XMLNS_NS, namespacePrefix); + } + + if (!nsDeclaredOnElement) { + // Namspace for element was not declared on the element itself, see if the namespace is declared on + // an ancestral element within the subtree where namespaces much be rooted + namespaceURI = lookupNamespaceURI(domElement, upperNamespaceSearchBound, namespacePrefix); + + if (namespaceURI == null) { + // Namespace for the element is not declared on any ancestral nodes within the subtree where namespaces + // must be rooted. Resolve the namespace from ancestors outside that subtree. + namespaceURI = lookupNamespaceURI(upperNamespaceSearchBound, null, namespacePrefix); + if (namespaceURI != null) { + // Namespace resolved outside the subtree where namespaces must be declared so declare the namespace + // on this element (within the subtree). + appendNamespaceDeclaration(domElement, namespaceURI, namespacePrefix); + } else { + // Namespace couldn't be resolved from any ancestor. If the namespace prefix is null then the + // element is simply in the undeclared default document namespace, which is fine. If it isn't null + // then a namespace prefix, that hasn't properly been declared, is being used. + if (namespacePrefix != null) { + throw new XMLParserException("Unable to resolve namespace prefix " + namespacePrefix + + " found on element " + getNodeQName(domElement)); + } + } + } + } + + // Make sure all the attribute URIs are rooted here or have been rooted in an ancestor + NamedNodeMap attributes = domElement.getAttributes(); + Node attributeNode; + for (int i = 0; i < attributes.getLength(); i++) { + namespacePrefix = null; + namespaceURI = null; + attributeNode = attributes.item(i); + + // Shouldn't need this check, but just to be safe, we have it + if (attributeNode.getNodeType() != Node.ATTRIBUTE_NODE) { + continue; + } + + namespacePrefix = attributeNode.getPrefix(); + if (!DatatypeHelper.isEmpty(namespacePrefix)) { + // If it's the "xmlns" prefix then it is the namespace declaration, + // don't try to look it up and redeclare it + if (namespacePrefix.equals(XMLConstants.XMLNS_PREFIX) + || namespacePrefix.equals(XMLConstants.XML_PREFIX)) { + continue; + } + + // check to see if the namespace for the prefix has already been defined within the XML fragment + namespaceURI = lookupNamespaceURI(domElement, upperNamespaceSearchBound, namespacePrefix); + if (namespaceURI == null) { + namespaceURI = lookupNamespaceURI(upperNamespaceSearchBound, null, namespacePrefix); + if (namespaceURI == null) { + throw new XMLParserException("Unable to resolve namespace prefix " + namespacePrefix + + " found on attribute " + getNodeQName(attributeNode) + " found on element " + + getNodeQName(domElement)); + } + + appendNamespaceDeclaration(domElement, namespaceURI, namespacePrefix); + } + } + } + + // Now for the child elements, we pass a copy of the resolved namespace list in order to + // maintain proper scoping of namespaces. + NodeList childNodes = domElement.getChildNodes(); + Node childNode; + for (int i = 0; i < childNodes.getLength(); i++) { + childNode = childNodes.item(i); + if (childNode.getNodeType() == Node.ELEMENT_NODE) { + rootNamespaces((Element) childNode, upperNamespaceSearchBound); + } + } + } + + /** + * Shortcut for checking a DOM element node's namespace and local name. + * + * @param e An element to compare against + * @param ns An XML namespace to compare + * @param localName A local name to compare + * @return true iff the element's local name and namespace match the parameters + */ + public static boolean isElementNamed(Element e, String ns, String localName) { + return e != null && DatatypeHelper.safeEquals(ns, e.getNamespaceURI()) + && DatatypeHelper.safeEquals(localName, e.getLocalName()); + } + + /** + * Gets the first child Element of the node, skipping any Text nodes such as whitespace. + * + * @param n The parent in which to search for children + * @return The first child Element of n, or null if none + */ + public static Element getFirstChildElement(Node n) { + Node child = n.getFirstChild(); + while (child != null && child.getNodeType() != Node.ELEMENT_NODE) { + child = child.getNextSibling(); + } + + if (child != null) { + return (Element) child; + } else { + return null; + } + } + + /** + * Gets the next sibling Element of the node, skipping any Text nodes such as whitespace. + * + * @param n The sibling to start with + * @return The next sibling Element of n, or null if none + */ + public static Element getNextSiblingElement(Node n) { + Node sib = n.getNextSibling(); + while (sib != null && sib.getNodeType() != Node.ELEMENT_NODE) { + sib = sib.getNextSibling(); + } + + if (sib != null) { + return (Element) sib; + } else { + return null; + } + } + + /** + * Converts a lexical duration, as defined by XML Schema 1.0, into milliseconds. + * + * @param duration lexical duration representation + * + * @return duration in milliseconds + */ + public static long durationToLong(String duration) { + Duration xmlDuration = getDataTypeFactory().newDuration(duration); + return xmlDuration.getTimeInMillis(new GregorianCalendar()); + } + + /** + * Converts a duration in milliseconds to a lexical duration, as defined by XML Schema 1.0. + * + * @param duration the duration + * + * @return the lexical representation + */ + public static String longToDuration(long duration) { + Duration xmlDuration = getDataTypeFactory().newDuration(duration); + return xmlDuration.toString(); + } + +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/util/XMLObjectChildrenList.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/util/XMLObjectChildrenList.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/util/XMLObjectChildrenList.java 17 Aug 2012 15:17:17 -0000 1.1 @@ -0,0 +1,209 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.util; + +import java.util.AbstractList; +import java.util.Collection; +import java.util.List; + +import org.opensaml.xml.XMLObject; + +/** + * Resizable list for the children of XMLObjects. This list implements all optional List operations and does not all for + * null elements. XMLObjects added to, or removed from, this list will have their parent object appropriately set and, + * the underlying DOM will be released during mutation opertions. + * + * @param type of elements added to the list + */ +public class XMLObjectChildrenList extends AbstractList { + + /** Parent to the elements in this list. */ + private XMLObject parent; + + /** List of elements. */ + private List elements; + + /** + * Constructs an empty list with all added XMLObjects being assigned the given parent XMLObject. + * + * @param newParent the parent for all the added XMLObjects + * + * @throws NullPointerException thrown if the parent is null + */ + public XMLObjectChildrenList(XMLObject newParent) throws NullPointerException { + if (newParent == null) { + throw new NullPointerException("Parent may not be null"); + } + + parent = newParent; + elements = new LazyList(); + } + + /** + * Constructs a list containing the elements in the specified collection, in the order they are returned by the + * collection's iterator, with each added XMLObject assigned the given parent XMLObject. + * + * @param newParent the parent for all the added XMLObjects + * @param newElements the elements to be added + * + * @throws NullPointerException thrown if the parent is null + * @throws IllegalArgumentException thrown if any of the XMLObjects in the given collection already have a parent + * that is different from the given parent + */ + public XMLObjectChildrenList(XMLObject newParent, Collection newElements) throws NullPointerException { + if (newParent == null) { + throw new NullPointerException("Parent may not be null"); + } + + parent = newParent; + elements = new LazyList(); + + addAll(newElements); + } + + /** {@inheritDoc} */ + public int size() { + return elements.size(); + } + + /** + * Checks to see if the given element is contained in this list. + * + * @param element the element to check for + * + * @return true if the element is in this list, false if not + */ + public boolean contains(ElementType element) { + return elements.contains(element); + } + + /** {@inheritDoc} */ + public ElementType get(int index) { + return elements.get(index); + } + + /** + * Replaces the XMLObject at the specified index with the given element. + * + * @param index index of the XMLObject to be replaced + * @param element element to be stored at the given index + * + * @return the replaced XMLObject + * + * @throws IllegalArgumentException thrown if the given XMLObject already has a parent that is different from the + * XMLObject given at list construction time + */ + public ElementType set(int index, ElementType element) throws IllegalArgumentException { + if (element == null) { + return null; + } + + setParent(element); + + ElementType removedElement = elements.set(index, element); + if (removedElement != null) { + removedElement.setParent(null); + parent.getIDIndex().deregisterIDMappings(removedElement.getIDIndex()); + } + + // Note: to avoid ordering problems, this needs to be called after + // the deregistration, in case the added element has a same ID string + // value as the removed one, else you will lose it. + parent.getIDIndex().registerIDMappings(element.getIDIndex()); + + modCount++; + return removedElement; + } + + /** + * Adds the given XMLObject to this list. + * + * @param index index at which to add the given XMLObject + * @param element element to be stored at the given index + * + * @throws IllegalArgumentException thrown if the given XMLObject already has a parent that is different from the + * XMLObject given at list construction time + */ + public void add(int index, ElementType element) throws IllegalArgumentException { + if (element == null || elements.contains(element)) { + return; + } + + setParent(element); + parent.getIDIndex().registerIDMappings(element.getIDIndex()); + + modCount++; + elements.add(index, element); + } + + /** {@inheritDoc} */ + public ElementType remove(int index) { + ElementType element = elements.remove(index); + + if (element != null) { + element.releaseParentDOM(true); + element.setParent(null); + parent.getIDIndex().deregisterIDMappings(element.getIDIndex()); + } + + modCount++; + return element; + } + + /** + * Removes the element from the list. + * + * @param element the element to be removed + * + * @return true if the element was in the list and removed, false if not + */ + public boolean remove(ElementType element) { + boolean elementRemoved = false; + + elementRemoved = elements.remove(element); + if (elementRemoved) { + if (element != null) { + element.releaseParentDOM(true); + element.setParent(null); + parent.getIDIndex().deregisterIDMappings(element.getIDIndex()); + } + } + + return elementRemoved; + } + + /** + * Assigned the parent, given at list construction, to the given element if the element does not have a parent or + * its parent matches the one given at list construction time. + * + * @param element the element to set the parent on + * + * @throws IllegalArgumentException thrown if the given element already has a parent and it is different than the + * parent given at list construction time + */ + protected void setParent(ElementType element) throws IllegalArgumentException { + XMLObject elemParent = element.getParent(); + if (elemParent != null && elemParent != parent) { + throw new IllegalArgumentException(element.getElementQName() + + " is already the child of another XMLObject and may not be inserted in to this list"); + } + + element.setParent(parent); + element.releaseParentDOM(true); + } +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/util/XMLObjectHelper.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/util/XMLObjectHelper.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/util/XMLObjectHelper.java 17 Aug 2012 15:17:17 -0000 1.1 @@ -0,0 +1,317 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.util; + +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Reader; +import java.io.Writer; + +import org.opensaml.xml.Configuration; +import org.opensaml.xml.Namespace; +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.XMLRuntimeException; +import org.opensaml.xml.io.Marshaller; +import org.opensaml.xml.io.MarshallingException; +import org.opensaml.xml.io.Unmarshaller; +import org.opensaml.xml.io.UnmarshallingException; +import org.opensaml.xml.parse.ParserPool; +import org.opensaml.xml.parse.XMLParserException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.w3c.dom.Document; +import org.w3c.dom.Element; + + +/** + * A helper class for working with XMLObjects. + */ +public final class XMLObjectHelper { + + /** Constructor. */ + private XMLObjectHelper() { } + + /** + * Clone an XMLObject by brute force: + * + *

+ * 1) Marshall the original object if necessary + * 2) Clone the resulting DOM Element + * 3) Unmarshall a new XMLObject tree around it. + *

+ * + *

+ * This method variant is equivalent to cloneXMLObject(originalXMLObject, false). + *

+ * + * + * @param originalXMLObject the object to be cloned + * @return a clone of the original object + * + * @throws MarshallingException if original object can not be marshalled + * @throws UnmarshallingException if cloned object tree can not be unmarshalled + * + * @param the type of object being cloned + */ + public static T cloneXMLObject(T originalXMLObject) + throws MarshallingException, UnmarshallingException { + return cloneXMLObject(originalXMLObject, false); + } + + /** + * Clone an XMLObject by brute force: + * + *

+ * 1) Marshall the original object if necessary + * 2) Clone the resulting DOM Element + * 3) Unmarshall a new XMLObject tree around it. + *

+ * + * @param originalXMLObject the object to be cloned + * @param rootInNewDocument if true the cloned object's cached DOM will be rooted + * in a new Document; if false, the original object's underlying DOM is cloned, + * but the cloned copy remains unrooted and owned by the original Document + * @return a clone of the original object + * + * @throws MarshallingException if original object can not be marshalled + * @throws UnmarshallingException if cloned object tree can not be unmarshalled + * + * @param the type of object being cloned + */ + public static T cloneXMLObject(T originalXMLObject, boolean rootInNewDocument) + throws MarshallingException, UnmarshallingException { + + if (originalXMLObject == null) { + return null; + } + + Marshaller marshaller = Configuration.getMarshallerFactory().getMarshaller(originalXMLObject); + Element origElement = marshaller.marshall(originalXMLObject); + + Element clonedElement = null; + + if (rootInNewDocument) { + try { + Document newDocument = Configuration.getParserPool().newDocument(); + // Note: importNode copies the node tree and does not modify the source document + clonedElement = (Element) newDocument.importNode(origElement, true); + newDocument.appendChild(clonedElement); + } catch (XMLParserException e) { + throw new XMLRuntimeException("Error obtaining new Document from parser pool", e); + } + } else { + clonedElement = (Element) origElement.cloneNode(true); + } + + Unmarshaller unmarshaller = Configuration.getUnmarshallerFactory().getUnmarshaller(clonedElement); + T clonedXMLObject = (T) unmarshaller.unmarshall(clonedElement); + + return clonedXMLObject; + } + + /** + * Unmarshall a Document from an InputSteam. + * + * @param parserPool the ParserPool instance to use + * @param inputStream the InputStream to unmarshall + * @return the unmarshalled XMLObject + * @throws XMLParserException if there is a problem parsing the input data + * @throws UnmarshallingException if there is a problem unmarshalling the parsed DOM + */ + public static XMLObject unmarshallFromInputStream(ParserPool parserPool, InputStream inputStream) + throws XMLParserException, UnmarshallingException { + Logger log = getLogger(); + log.debug("Parsing InputStream into DOM document"); + + Document messageDoc = parserPool.parse(inputStream); + Element messageElem = messageDoc.getDocumentElement(); + + if (log.isTraceEnabled()) { + log.trace("Resultant DOM message was:"); + log.trace(XMLHelper.nodeToString(messageElem)); + } + + log.debug("Unmarshalling DOM parsed from InputStream"); + Unmarshaller unmarshaller = Configuration.getUnmarshallerFactory().getUnmarshaller(messageElem); + if (unmarshaller == null) { + log.error("Unable to unmarshall InputStream, no unmarshaller registered for element " + + XMLHelper.getNodeQName(messageElem)); + throw new UnmarshallingException( + "Unable to unmarshall InputStream, no unmarshaller registered for element " + + XMLHelper.getNodeQName(messageElem)); + } + + XMLObject message = unmarshaller.unmarshall(messageElem); + + log.debug("InputStream succesfully unmarshalled"); + return message; + } + + /** + * Unmarshall a Document from a Reader. + * + * @param parserPool the ParserPool instance to use + * @param reader the Reader to unmarshall + * @return the unmarshalled XMLObject + * @throws XMLParserException if there is a problem parsing the input data + * @throws UnmarshallingException if there is a problem unmarshalling the parsed DOM + */ + public static XMLObject unmarshallFromReader(ParserPool parserPool, Reader reader) + throws XMLParserException, UnmarshallingException { + Logger log = getLogger(); + log.debug("Parsing Reader into DOM document"); + + + Document messageDoc = parserPool.parse(reader); + Element messageElem = messageDoc.getDocumentElement(); + + if (log.isTraceEnabled()) { + log.trace("Resultant DOM message was:"); + log.trace(XMLHelper.nodeToString(messageElem)); + } + + log.debug("Unmarshalling DOM parsed from Reader"); + Unmarshaller unmarshaller = Configuration.getUnmarshallerFactory().getUnmarshaller(messageElem); + if (unmarshaller == null) { + log.error("Unable to unmarshall Reader, no unmarshaller registered for element " + + XMLHelper.getNodeQName(messageElem)); + throw new UnmarshallingException( + "Unable to unmarshall Reader, no unmarshaller registered for element " + + XMLHelper.getNodeQName(messageElem)); + } + + XMLObject message = unmarshaller.unmarshall(messageElem); + + log.debug("Reader succesfully unmarshalled"); + return message; + } + + /** + * Marshall an XMLObject. If the XMLObject already has a cached DOM via {@link XMLObject#getDOM()}, + * that Element will be returned. Otherwise the object will be fully marshalled and that Element returned. + * + * @param xmlObject the XMLObject to marshall + * @return the marshalled Element + * @throws MarshallingException if there is a problem marshalling the XMLObject + */ + public static Element marshall(XMLObject xmlObject) throws MarshallingException { + Logger log = getLogger(); + log.debug("Marshalling XMLObject"); + + if (xmlObject.getDOM() != null) { + log.debug("XMLObject already had cached DOM, returning that element"); + return xmlObject.getDOM(); + } + + Marshaller marshaller = Configuration.getMarshallerFactory().getMarshaller(xmlObject); + if (marshaller == null) { + log.error("Unable to marshall XMLOBject, no marshaller registered for object: " + + xmlObject.getElementQName()); + } + + Element messageElem = marshaller.marshall(xmlObject); + + if (log.isTraceEnabled()) { + log.trace("Marshalled XMLObject into DOM:"); + log.trace(XMLHelper.nodeToString(messageElem)); + } + + return messageElem; + } + + /** + * Marshall an XMLObject to an OutputStream. + * + * @param xmlObject the XMLObject to marshall + * @param outputStream the OutputStream to which to marshall + * @throws MarshallingException if there is a problem marshalling the object + */ + public static void marshallToOutputStream(XMLObject xmlObject, OutputStream outputStream) + throws MarshallingException { + Element element = marshall(xmlObject); + XMLHelper.writeNode(element, outputStream); + } + + /** + * Marshall an XMLObject to a Writer. + * + * @param xmlObject the XMLObject to marshall + * @param writer the Writer to which to marshall + * @throws MarshallingException if there is a problem marshalling the object + */ + public static void marshallToWriter(XMLObject xmlObject, Writer writer) throws MarshallingException { + Element element = marshall(xmlObject); + XMLHelper.writeNode(element, writer); + } + + /** + * Get the namespace URI bound to the specified prefix within the scope of the specified + * XMLObject. + * + * @param xmlObject the XMLObject from which to search + * @param prefix the prefix to search + * @return the namespace URI bound to the prefix, or none if not found + */ + public static String lookupNamespaceURI(XMLObject xmlObject, String prefix) { + XMLObject current = xmlObject; + + while (current != null) { + for (Namespace ns : current.getNamespaces()) { + if (DatatypeHelper.safeEquals(ns.getNamespacePrefix(), prefix)) { + return ns.getNamespaceURI(); + } + } + current = current.getParent(); + } + + return null; + } + + /** + * Get the prefix bound to the specified namespace URI within the scope of the specified + * XMLObject. + * + * @param xmlObject the XMLObject from which to search + * @param namespaceURI the namespace URI to search + * @return the prefix bound to the namespace URI, or none if not found + */ + public static String lookupNamespacePrefix(XMLObject xmlObject, String namespaceURI) { + XMLObject current = xmlObject; + + while (current != null) { + for (Namespace ns : current.getNamespaces()) { + if (DatatypeHelper.safeEquals(ns.getNamespaceURI(), namespaceURI)) { + return ns.getNamespacePrefix(); + } + } + current = current.getParent(); + } + + return null; + } + + /** + * Get an SLF4J Logger. + * + * @return a Logger instance + */ + private static Logger getLogger() { + return LoggerFactory.getLogger(XMLObjectHelper.class); + } + +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/util/package.html =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/util/package.html,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/util/package.html 17 Aug 2012 15:17:17 -0000 1.1 @@ -0,0 +1,6 @@ + + +Utility classes for working with XML, XMLObjects, and various data types. + + + \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/validation/AbstractValidatingXMLObject.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/validation/AbstractValidatingXMLObject.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/validation/AbstractValidatingXMLObject.java 17 Aug 2012 15:17:19 -0000 1.1 @@ -0,0 +1,112 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.validation; + +import java.util.Collections; +import java.util.List; + +import org.opensaml.xml.AbstractXMLObject; +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.util.LazyList; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Extension of {@link org.opensaml.xml.AbstractXMLObject} that implements + * {@link org.opensaml.xml.validation.ValidatingXMLObject}. + */ +public abstract class AbstractValidatingXMLObject extends AbstractXMLObject implements ValidatingXMLObject { + + /** Class logger. */ + private final Logger log = LoggerFactory.getLogger(AbstractValidatingXMLObject.class); + + /** Validators used to validate this XMLObject. */ + private List validators; + + /** + * Constructor. + * + * @param namespaceURI the namespace the element is in + * @param elementLocalName the local name of the XML element this Object represents + * @param namespacePrefix the prefix for the given namespace + */ + protected AbstractValidatingXMLObject(String namespaceURI, String elementLocalName, String namespacePrefix) { + super(namespaceURI, elementLocalName, namespacePrefix); + validators = new LazyList(); + } + + /** {@inheritDoc} */ + public List getValidators() { + if (validators.size() > 0) { + return Collections.unmodifiableList(validators); + } + + return null; + } + + /** {@inheritDoc} */ + public void registerValidator(Validator validator) { + if (validator != null) { + validators.add(validator); + } + } + + /** {@inheritDoc} */ + public void deregisterValidator(Validator validator) { + validators.remove(validator); + } + + /** {@inheritDoc} */ + public void validate(boolean validateDescendants) throws ValidationException { + for (Validator validator : validators) { + log.debug("Validating {} using Validator class {}", getElementQName(), validator.getClass().getName()); + validator.validate(this); + } + + if (validateDescendants) { + log.debug("Validating descendants of {}", getElementQName()); + validateChildren(this); + } + } + + /** + * Recursive method used to validate all the children of the given XMLObject that implement + * {@link ValidatingXMLObject}. Note, this can be a very expensive operation. + * + * @param xmlObject xmlObject whose descendants should be validated + * + * @throws ValidationException thrown if any child objects are not valid + */ + protected void validateChildren(XMLObject xmlObject) throws ValidationException { + for (XMLObject childObject : xmlObject.getOrderedChildren()) { + if(childObject == null){ + continue; + } + + if (childObject instanceof ValidatingXMLObject) { + ((ValidatingXMLObject) childObject).validate(false); + } else { + log.debug("{} does not implement ValidatingXMLObject, ignoring it.", childObject.getElementQName()); + } + + if (childObject.hasChildren()) { + validateChildren(childObject); + } + } + } +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/validation/ValidatingXMLObject.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/validation/ValidatingXMLObject.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/validation/ValidatingXMLObject.java 17 Aug 2012 15:17:19 -0000 1.1 @@ -0,0 +1,60 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.validation; + +import java.util.List; + +import org.opensaml.xml.XMLObject; + +/** + * A functional interface for XMLObjects that offer the ability + * to evaluate validation rules. + */ +public interface ValidatingXMLObject extends XMLObject{ + + /** + * Gets the list of validators for this XMLObject or null if there is no list. + * + * @return the list of validators for this XMLObject + */ + public List getValidators(); + + /** + * Registers a validator for this XMLObject. + * + * @param validator the validator + */ + public void registerValidator(Validator validator); + + /** + * Deregisters a validator for this XMLObject. + * + * @param validator the validator + */ + public void deregisterValidator(Validator validator); + + /** + * Validates this XMLObject against all registered validators. + * + * @param validateDescendants true if all the descendants of this object should + * be validated as well, false if not + * + * @throws ValidationException thrown if the element is not valid + */ + public void validate(boolean validateDescendants) throws ValidationException; +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/validation/ValidationException.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/validation/ValidationException.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/validation/ValidationException.java 17 Aug 2012 15:17:19 -0000 1.1 @@ -0,0 +1,62 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.validation; + +/** + * An exception indicating that a XMLObject is not valid. + */ +public class ValidationException extends Exception { + + /** Serial Version UID. */ + private static final long serialVersionUID = -8268522315645892798L; + + /** + * Constructor. + */ + public ValidationException() { + super(); + } + + /** + * Constructor. + * + * @param message exception message + */ + public ValidationException(String message) { + super(message); + } + + /** + * Constructor. + * + * @param wrappedException exception to be wrapped by this one + */ + public ValidationException(Exception wrappedException) { + super(wrappedException); + } + + /** + * Constructor. + * + * @param message exception message + * @param wrappedException exception to be wrapped by this one + */ + public ValidationException(String message, Exception wrappedException) { + super(message, wrappedException); + } +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/validation/Validator.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/validation/Validator.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/validation/Validator.java 17 Aug 2012 15:17:19 -0000 1.1 @@ -0,0 +1,38 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.validation; + +import org.opensaml.xml.XMLObject; + +/** + * An interface for classes that implement rules for checking the + * validity of a XMLObjects. + * + * @param type of XML object that will be validated + */ +public interface Validator { + + /** + * Checks to see if a XMLObject is valid. + * + * @param xmlObject the XMLObject to validate + * + * @throws ValidationException thrown if the element is not valid + */ + public void validate(XMLObjectType xmlObject) throws ValidationException; +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/validation/ValidatorSuite.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/validation/ValidatorSuite.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/validation/ValidatorSuite.java 17 Aug 2012 15:17:19 -0000 1.1 @@ -0,0 +1,176 @@ +/* + * Licensed to the University Corporation for Advanced Internet Development, + * Inc. (UCAID) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The UCAID licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opensaml.xml.validation; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import javax.xml.namespace.QName; + +import org.opensaml.xml.XMLObject; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * A collection of validators that can be applied to an XMLObject and its children. These collections can represent + * usage specific checks, such as those outlined in things like profiles for specific XML specification. + * + * Registered {@link org.opensaml.xml.validation.Validator}s must be stateless. The xmlObjectTarget may be the + * XMLObject's element QName retrieved by {@link org.opensaml.xml.XMLObject#getElementQName()} or schema type, retrieved + * by {@link org.opensaml.xml.XMLObject#getSchemaType()}, with schema type registered checks performed first. + */ +public class ValidatorSuite { + + /** Class logger. */ + private final Logger log = LoggerFactory.getLogger(ValidatorSuite.class); + + /** Unique ID for this suite. */ + private String id; + + /** Validators registered in this suite. */ + private Map> validators; + + /** + * Constructor. + * + * @param suiteId unique ID for this suite + */ + public ValidatorSuite(String suiteId) { + validators = new ConcurrentHashMap>(); + id = suiteId; + } + + /** + * Gets a unique ID for this suite. + * + * @return a unique ID for this suite + */ + public String getId() { + return id; + } + + /** + * Evaluates the registered validators against the given XMLObject and it's children. + * + * @param xmlObject the XMLObject to validate + * + * @throws ValidationException thrown if the element is not valid + */ + public void validate(XMLObject xmlObject) throws ValidationException { + if (xmlObject == null) { + return; + } + + log.debug("Beginning to verify XMLObject {} and its children", xmlObject.getElementQName()); + performValidation(xmlObject); + + List children = xmlObject.getOrderedChildren(); + if (children != null) { + for (XMLObject child : children) { + validate(child); + } + } + } + + /** + * Gets an immutable list of validators for a given XMLObject target. + * + * @param xmlObjectTarget the XMLObject the returned list of validators operates on + * + * @return the list of validators for the XMLObject + */ + public List getValidators(QName xmlObjectTarget) { + return Collections.unmodifiableList(validators.get(xmlObjectTarget)); + } + + /** + * Registers a new validator in the suite. + * + * @param validator the validator + * @param xmlObjectTarget the XMLObject the validator should operate on + */ + public void registerValidator(QName xmlObjectTarget, Validator validator) { + List targetValidators = validators.get(xmlObjectTarget); + + if (targetValidators == null) { + targetValidators = new ArrayList(); + validators.put(xmlObjectTarget, targetValidators); + } + + targetValidators.add(validator); + } + + /** + * Removes a validator from this suite. + * + * @param xmlObjectTarget the XMLObject the validator is currently registered for + * @param validator the validator to remove + */ + public void deregisterValidator(QName xmlObjectTarget, Validator validator) { + List targetValidators = validators.get(xmlObjectTarget); + + if (targetValidators != null) { + targetValidators.remove(validator); + } + } + + /** + * Validates the given XMLObject. Does NOT validate its children. + * + * @param xmlObject the XMLObject to validate. + * + * @throws ValidationException thrown if the XMLObject does not validate + */ + private void performValidation(XMLObject xmlObject) throws ValidationException { + QName schemaType = xmlObject.getSchemaType(); + if (schemaType != null) { + log.debug("Validating XMLObject {} against validators registered under its schema type {}", xmlObject + .getElementQName(), schemaType); + performValidation(schemaType, xmlObject); + } + + log.debug("Validating XMLObject {} against validators registered under its element QName", xmlObject + .getElementQName()); + performValidation(xmlObject.getElementQName(), xmlObject); + } + + /** + * Validates the given XMLObject against the validators registered under the given key. + * + * @param validatorSetKey the key to the list of validators + * @param xmlObject the XMLObject to validate + * + * @throws ValidationException thrown if any validations fail + */ + private void performValidation(QName validatorSetKey, XMLObject xmlObject) throws ValidationException { + List elementQNameValidators = validators.get(validatorSetKey); + if (elementQNameValidators != null) { + for (Validator validator : elementQNameValidators) { + log.debug("Validating XMLObject {} against Validator {}", xmlObject.getElementQName(), validator + .getClass().getName()); + validator.validate(xmlObject); + } + } else { + log.debug("No validators registered for XMLObject {} under QName {}", xmlObject.getElementQName(), + validatorSetKey); + } + } +} \ No newline at end of file Index: 3rdParty_sources/xmltooling/org/opensaml/xml/validation/package.html =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/xmltooling/org/opensaml/xml/validation/package.html,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/xmltooling/org/opensaml/xml/validation/package.html 17 Aug 2012 15:17:19 -0000 1.1 @@ -0,0 +1,5 @@ + + +Interfaces for classes that may be used to validate trees of XMLObjects. + + \ No newline at end of file