| /** |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package org.apache.activemq.ra; |
| |
| import java.beans.IntrospectionException; |
| import java.beans.PropertyDescriptor; |
| import java.io.Serializable; |
| import java.util.ArrayList; |
| import java.util.Iterator; |
| import java.util.List; |
| |
| import javax.jms.Queue; |
| import javax.jms.Session; |
| import javax.jms.Topic; |
| import javax.resource.ResourceException; |
| import javax.resource.spi.InvalidPropertyException; |
| import javax.resource.spi.ResourceAdapter; |
| |
| import org.apache.activemq.RedeliveryPolicy; |
| import org.apache.activemq.command.ActiveMQDestination; |
| import org.apache.activemq.command.ActiveMQQueue; |
| import org.apache.activemq.command.ActiveMQTopic; |
| import org.apache.activemq.selector.SelectorParser; |
| |
| /** |
| * Configures the inbound JMS consumer specification using ActiveMQ |
| * |
| * @org.apache.xbean.XBean element="activationSpec" |
| * $Date: 2007-08-11 17:29:21 -0400 (Sat, 11 Aug |
| * 2007) $ |
| */ |
| public class ActiveMQActivationSpec implements MessageActivationSpec, Serializable { |
| |
| /** Auto-acknowledge constant for <code>acknowledgeMode</code> property * */ |
| public static final String AUTO_ACKNOWLEDGE_MODE = "Auto-acknowledge"; |
| /** Dups-ok-acknowledge constant for <code>acknowledgeMode</code> property * */ |
| public static final String DUPS_OK_ACKNOWLEDGE_MODE = "Dups-ok-acknowledge"; |
| /** Durable constant for <code>subscriptionDurability</code> property * */ |
| public static final String DURABLE_SUBSCRIPTION = "Durable"; |
| /** NonDurable constant for <code>subscriptionDurability</code> property * */ |
| public static final String NON_DURABLE_SUBSCRIPTION = "NonDurable"; |
| public static final int INVALID_ACKNOWLEDGE_MODE = -1; |
| |
| private static final long serialVersionUID = -7153087544100459975L; |
| |
| private transient MessageResourceAdapter resourceAdapter; |
| private String destinationType; |
| private String messageSelector; |
| private String destination; |
| private String acknowledgeMode = AUTO_ACKNOWLEDGE_MODE; |
| private String userName; |
| private String password; |
| private String clientId; |
| private String subscriptionName; |
| private String subscriptionDurability = NON_DURABLE_SUBSCRIPTION; |
| private String noLocal = "false"; |
| private String useRAManagedTransaction = "false"; |
| private String maxSessions = "10"; |
| private String maxMessagesPerSessions = "10"; |
| private String enableBatch = "false"; |
| private String maxMessagesPerBatch = "10"; |
| private String trustStore; |
| private String trustStorePassword; |
| private String keyStore; |
| private String keyStorePassword; |
| private String keyStoreKeyPassword; |
| private RedeliveryPolicy redeliveryPolicy; |
| private boolean useJndi; |
| |
| /** |
| * @see javax.resource.spi.ActivationSpec#validate() |
| */ |
| public void validate() throws InvalidPropertyException { |
| List<String> errorMessages = new ArrayList<String>(); |
| List<PropertyDescriptor> propsNotSet = new ArrayList<PropertyDescriptor>(); |
| try { |
| if (!isValidDestination(errorMessages)) { |
| propsNotSet.add(new PropertyDescriptor("destination", ActiveMQActivationSpec.class)); |
| } |
| if (!isValidDestinationType(errorMessages)) { |
| propsNotSet.add(new PropertyDescriptor("destinationType", ActiveMQActivationSpec.class)); |
| } |
| if (!isValidAcknowledgeMode(errorMessages)) { |
| propsNotSet.add(new PropertyDescriptor("acknowledgeMode", ActiveMQActivationSpec.class)); |
| } |
| if (!isValidSubscriptionDurability(errorMessages)) { |
| propsNotSet.add(new PropertyDescriptor("subscriptionDurability", ActiveMQActivationSpec.class)); |
| } |
| if (!isValidClientId(errorMessages)) { |
| propsNotSet.add(new PropertyDescriptor("clientId", ActiveMQActivationSpec.class)); |
| } |
| if (!isValidSubscriptionName(errorMessages)) { |
| propsNotSet.add(new PropertyDescriptor("subscriptionName", ActiveMQActivationSpec.class)); |
| } |
| if (!isValidMaxMessagesPerSessions(errorMessages)) { |
| propsNotSet.add(new PropertyDescriptor("maxMessagesPerSessions", ActiveMQActivationSpec.class)); |
| } |
| if (!isValidMaxSessions(errorMessages)) { |
| propsNotSet.add(new PropertyDescriptor("maxSessions", ActiveMQActivationSpec.class)); |
| } |
| if (!isValidMessageSelector(errorMessages)) { |
| propsNotSet.add(new PropertyDescriptor("messageSelector", ActiveMQActivationSpec.class)); |
| } |
| if (!isValidNoLocal(errorMessages)) { |
| propsNotSet.add(new PropertyDescriptor("noLocal", ActiveMQActivationSpec.class)); |
| } |
| if (!isValidUseRAManagedTransaction(errorMessages)) { |
| propsNotSet.add(new PropertyDescriptor("useRAManagedTransaction", ActiveMQActivationSpec.class)); |
| } |
| if (!isValidEnableBatch(errorMessages)) { |
| propsNotSet.add(new PropertyDescriptor("enableBatch", ActiveMQActivationSpec.class)); |
| } |
| if (!isValidMaxMessagesPerBatch(errorMessages)) { |
| propsNotSet.add(new PropertyDescriptor("maxMessagesPerBatch", ActiveMQActivationSpec.class)); |
| } |
| |
| } catch (IntrospectionException e) { |
| e.printStackTrace(); |
| } |
| |
| if (propsNotSet.size() > 0) { |
| StringBuffer b = new StringBuffer(); |
| b.append("Invalid settings:"); |
| for (Iterator<String> iter = errorMessages.iterator(); iter.hasNext();) { |
| b.append(" "); |
| b.append(iter.next()); |
| } |
| InvalidPropertyException e = new InvalidPropertyException(b.toString()); |
| final PropertyDescriptor[] descriptors = propsNotSet.toArray(new PropertyDescriptor[propsNotSet.size()]); |
| e.setInvalidPropertyDescriptors(descriptors); |
| throw e; |
| } |
| } |
| |
| public boolean isValidUseRAManagedTransaction(List<String> errorMessages) { |
| try { |
| new Boolean(useRAManagedTransaction); |
| return true; |
| } catch (Throwable e) { |
| // |
| } |
| errorMessages.add("useRAManagedTransaction must be set to: true or false."); |
| return false; |
| } |
| |
| public boolean isValidNoLocal(List<String> errorMessages) { |
| try { |
| new Boolean(noLocal); |
| return true; |
| } catch (Throwable e) { |
| // |
| } |
| errorMessages.add("noLocal must be set to: true or false."); |
| return false; |
| } |
| |
| public boolean isValidMessageSelector(List<String> errorMessages) { |
| try { |
| if (!isEmpty(messageSelector)) { |
| SelectorParser.parse(messageSelector); |
| } |
| return true; |
| } catch (Throwable e) { |
| errorMessages.add("messageSelector not set to valid message selector: " + e); |
| return false; |
| } |
| } |
| |
| public boolean isValidMaxSessions(List<String> errorMessages) { |
| try { |
| if (Integer.parseInt(maxSessions) > 0) { |
| return true; |
| } |
| } catch (NumberFormatException e) { |
| // |
| } |
| errorMessages.add("maxSessions must be set to number > 0"); |
| return false; |
| } |
| |
| public boolean isValidMaxMessagesPerSessions(List<String> errorMessages) { |
| try { |
| if (Integer.parseInt(maxMessagesPerSessions) > 0) { |
| return true; |
| } |
| } catch (NumberFormatException e) { |
| // |
| } |
| errorMessages.add("maxMessagesPerSessions must be set to number > 0"); |
| return false; |
| } |
| |
| public boolean isValidMaxMessagesPerBatch(List<String> errorMessages) { |
| try { |
| if (Integer.parseInt(maxMessagesPerBatch) > 0) { |
| return true; |
| } |
| } catch (NumberFormatException e) { |
| // |
| } |
| errorMessages.add("maxMessagesPerBatch must be set to number > 0"); |
| return false; |
| } |
| |
| public boolean isValidEnableBatch(List<String> errorMessages) { |
| try { |
| new Boolean(enableBatch); |
| return true; |
| } catch (Throwable e) { |
| // |
| } |
| errorMessages.add("enableBatch must be set to: true or false"); |
| return false; |
| } |
| |
| public ResourceAdapter getResourceAdapter() { |
| return resourceAdapter; |
| } |
| |
| /** |
| * @see javax.resource.spi.ResourceAdapterAssociation#setResourceAdapter(javax.resource.spi.ResourceAdapter) |
| */ |
| public void setResourceAdapter(ResourceAdapter resourceAdapter) throws ResourceException { |
| // spec section 5.3.3 |
| if (this.resourceAdapter != null) { |
| throw new ResourceException("ResourceAdapter already set"); |
| } |
| if (!(resourceAdapter instanceof MessageResourceAdapter)) { |
| throw new ResourceException("ResourceAdapter is not of type: " + MessageResourceAdapter.class.getName()); |
| } |
| this.resourceAdapter = (MessageResourceAdapter)resourceAdapter; |
| } |
| |
| // /////////////////////////////////////////////////////////////////////// |
| // |
| // Java Bean getters and setters for this ActivationSpec class. |
| // |
| // /////////////////////////////////////////////////////////////////////// |
| public String getDestinationType() { |
| if (!isEmpty(destinationType)) { |
| return destinationType; |
| } |
| return null; |
| } |
| |
| /** |
| * @param destinationType The destinationType to set. |
| */ |
| public void setDestinationType(String destinationType) { |
| this.destinationType = destinationType; |
| } |
| |
| public String getPassword() { |
| if (!isEmpty(password)) { |
| return password; |
| } |
| return null; |
| } |
| |
| /** |
| * |
| */ |
| public void setPassword(String password) { |
| this.password = password; |
| } |
| |
| public String getUserName() { |
| if (!isEmpty(userName)) { |
| return userName; |
| } |
| return null; |
| } |
| |
| /** |
| * |
| */ |
| public void setUserName(String userName) { |
| this.userName = userName; |
| } |
| |
| public String getMessageSelector() { |
| if (!isEmpty(messageSelector)) { |
| return messageSelector; |
| } |
| return null; |
| } |
| |
| /** |
| * @param messageSelector The messageSelector to set. |
| */ |
| public void setMessageSelector(String messageSelector) { |
| this.messageSelector = messageSelector; |
| } |
| |
| public String getNoLocal() { |
| return noLocal; |
| } |
| |
| /** |
| * @param noLocal The noLocal to set. |
| */ |
| public void setNoLocal(String noLocal) { |
| if (noLocal != null) { |
| this.noLocal = noLocal; |
| } |
| } |
| |
| public String getAcknowledgeMode() { |
| if (!isEmpty(acknowledgeMode)) { |
| return acknowledgeMode; |
| } |
| return null; |
| } |
| |
| /** |
| * |
| */ |
| public void setAcknowledgeMode(String acknowledgeMode) { |
| this.acknowledgeMode = acknowledgeMode; |
| } |
| |
| public String getClientId() { |
| if (!isEmpty(clientId)) { |
| return clientId; |
| } |
| return null; |
| } |
| |
| /** |
| * |
| */ |
| public void setClientId(String clientId) { |
| this.clientId = clientId; |
| } |
| |
| public String getDestination() { |
| if (!isEmpty(destination)) { |
| return destination; |
| } |
| return null; |
| } |
| |
| /** |
| * |
| */ |
| public void setDestination(String destination) { |
| this.destination = destination; |
| } |
| |
| public String getSubscriptionDurability() { |
| if (!isEmpty(subscriptionDurability)) { |
| return subscriptionDurability; |
| } |
| return null; |
| } |
| |
| /** |
| * |
| */ |
| public void setSubscriptionDurability(String subscriptionDurability) { |
| this.subscriptionDurability = subscriptionDurability; |
| } |
| |
| public String getSubscriptionName() { |
| if (!isEmpty(subscriptionName)) { |
| return subscriptionName; |
| } |
| return null; |
| } |
| |
| /** |
| * |
| */ |
| public void setSubscriptionName(String subscriptionName) { |
| this.subscriptionName = subscriptionName; |
| } |
| |
| public boolean isValidSubscriptionName(List<String> errorMessages) { |
| if (!isDurableSubscription() ? true : subscriptionName != null && subscriptionName.trim().length() > 0) { |
| return true; |
| } |
| errorMessages.add("subscriptionName must be set since durable subscription was requested."); |
| return false; |
| } |
| |
| public boolean isValidClientId(List<String> errorMessages) { |
| if (!isDurableSubscription() ? true : clientId != null && clientId.trim().length() > 0) { |
| return true; |
| } |
| errorMessages.add("clientId must be set since durable subscription was requested."); |
| return false; |
| } |
| |
| public boolean isDurableSubscription() { |
| return DURABLE_SUBSCRIPTION.equals(subscriptionDurability); |
| } |
| |
| public boolean isValidSubscriptionDurability(List<String> errorMessages) { |
| // subscriptionDurability only applies to Topics |
| if (DURABLE_SUBSCRIPTION.equals(subscriptionDurability) && getDestinationType() != null && !Topic.class.getName().equals(getDestinationType())) { |
| errorMessages.add("subscriptionDurability cannot be set to: " + DURABLE_SUBSCRIPTION + " when destinationType is set to " + Queue.class.getName() |
| + " as it is only valid when destinationType is set to " + Topic.class.getName() + "."); |
| return false; |
| } |
| if (NON_DURABLE_SUBSCRIPTION.equals(subscriptionDurability) || DURABLE_SUBSCRIPTION.equals(subscriptionDurability)) { |
| return true; |
| } |
| errorMessages.add("subscriptionDurability must be set to: " + NON_DURABLE_SUBSCRIPTION + " or " + DURABLE_SUBSCRIPTION + "."); |
| return false; |
| } |
| |
| public boolean isValidAcknowledgeMode(List<String> errorMessages) { |
| if (AUTO_ACKNOWLEDGE_MODE.equals(acknowledgeMode) || DUPS_OK_ACKNOWLEDGE_MODE.equals(acknowledgeMode)) { |
| return true; |
| } |
| errorMessages.add("acknowledgeMode must be set to: " + AUTO_ACKNOWLEDGE_MODE + " or " + DUPS_OK_ACKNOWLEDGE_MODE + "."); |
| return false; |
| } |
| |
| public boolean isValidDestinationType(List<String> errorMessages) { |
| if (Queue.class.getName().equals(destinationType) || Topic.class.getName().equals(destinationType)) { |
| return true; |
| } |
| errorMessages.add("destinationType must be set to: " + Queue.class.getName() + " or " + Topic.class.getName() + "."); |
| return false; |
| } |
| |
| public boolean isValidDestination(List<String> errorMessages) { |
| if (!(destination == null || destination.equals(""))) { |
| return true; |
| } |
| errorMessages.add("destination is a required field and must be set to the destination name."); |
| return false; |
| } |
| |
| public boolean isEmpty(String value) { |
| return value == null || "".equals(value.trim()); |
| } |
| |
| /** |
| * |
| */ |
| @Override |
| public String toString() { |
| return "ActiveMQActivationSpec{" + "acknowledgeMode='" + acknowledgeMode + "'" + ", destinationType='" + destinationType + "'" + ", messageSelector='" + messageSelector + "'" |
| + ", destination='" + destination + "'" + ", clientId='" + clientId + "'" + ", subscriptionName='" + subscriptionName + "'" + ", subscriptionDurability='" + subscriptionDurability |
| + "'" + ", useJndi='"+ useJndi + "'" +"}"; |
| } |
| |
| public int getAcknowledgeModeForSession() { |
| if (AUTO_ACKNOWLEDGE_MODE.equals(acknowledgeMode)) { |
| return Session.AUTO_ACKNOWLEDGE; |
| } else if (DUPS_OK_ACKNOWLEDGE_MODE.equals(acknowledgeMode)) { |
| return Session.DUPS_OK_ACKNOWLEDGE; |
| } else { |
| return INVALID_ACKNOWLEDGE_MODE; |
| } |
| } |
| |
| /** |
| * A helper method mostly for use in Dependency Injection containers which |
| * allows you to customize the destination and destinationType properties |
| * from a single ActiveMQDestination POJO |
| */ |
| public void setActiveMQDestination(ActiveMQDestination destination) { |
| setDestination(destination.getPhysicalName()); |
| if (destination instanceof Queue) { |
| setDestinationType(Queue.class.getName()); |
| } else { |
| setDestinationType(Topic.class.getName()); |
| } |
| } |
| |
| /** |
| * |
| */ |
| public ActiveMQDestination createDestination() { |
| if (isEmpty(destinationType) || isEmpty(destination)) { |
| return null; |
| } |
| |
| ActiveMQDestination dest = null; |
| if (Queue.class.getName().equals(destinationType)) { |
| dest = new ActiveMQQueue(destination); |
| } else if (Topic.class.getName().equals(destinationType)) { |
| dest = new ActiveMQTopic(destination); |
| } else { |
| assert false : "Execution should never reach here"; |
| } |
| return dest; |
| } |
| |
| public String getMaxMessagesPerSessions() { |
| return maxMessagesPerSessions; |
| } |
| |
| /** |
| * |
| */ |
| public void setMaxMessagesPerSessions(String maxMessagesPerSessions) { |
| if (maxMessagesPerSessions != null) { |
| this.maxMessagesPerSessions = maxMessagesPerSessions; |
| } |
| } |
| |
| public String getMaxSessions() { |
| return maxSessions; |
| } |
| |
| /** |
| * |
| */ |
| public void setMaxSessions(String maxSessions) { |
| if (maxSessions != null) { |
| this.maxSessions = maxSessions; |
| } |
| } |
| |
| public String getUseRAManagedTransaction() { |
| return useRAManagedTransaction; |
| } |
| |
| /** |
| * |
| */ |
| public void setUseRAManagedTransaction(String useRAManagedTransaction) { |
| if (useRAManagedTransaction != null) { |
| this.useRAManagedTransaction = useRAManagedTransaction; |
| } |
| } |
| |
| public int getMaxMessagesPerSessionsIntValue() { |
| return Integer.parseInt(maxMessagesPerSessions); |
| } |
| |
| public int getMaxSessionsIntValue() { |
| return Integer.parseInt(maxSessions); |
| } |
| |
| public boolean isUseRAManagedTransactionEnabled() { |
| return Boolean.valueOf(useRAManagedTransaction).booleanValue(); |
| } |
| |
| public boolean getNoLocalBooleanValue() { |
| return Boolean.valueOf(noLocal).booleanValue(); |
| } |
| |
| public String getEnableBatch() { |
| return enableBatch; |
| } |
| |
| /** |
| * |
| */ |
| public void setEnableBatch(String enableBatch) { |
| if (enableBatch != null) { |
| this.enableBatch = enableBatch; |
| } |
| } |
| |
| public boolean getEnableBatchBooleanValue() { |
| return Boolean.valueOf(enableBatch).booleanValue(); |
| } |
| |
| public int getMaxMessagesPerBatchIntValue() { |
| return Integer.parseInt(maxMessagesPerBatch); |
| } |
| |
| public String getMaxMessagesPerBatch() { |
| return maxMessagesPerBatch; |
| } |
| |
| /** |
| * |
| */ |
| public void setMaxMessagesPerBatch(String maxMessagesPerBatch) { |
| if (maxMessagesPerBatch != null) { |
| this.maxMessagesPerBatch = maxMessagesPerBatch; |
| } |
| } |
| |
| public double getBackOffMultiplier() { |
| if (redeliveryPolicy == null) { |
| return 0; |
| } |
| return redeliveryPolicy.getBackOffMultiplier(); |
| } |
| |
| public long getInitialRedeliveryDelay() { |
| if (redeliveryPolicy == null) { |
| return 0; |
| } |
| return redeliveryPolicy.getInitialRedeliveryDelay(); |
| } |
| |
| public int getMaximumRedeliveries() { |
| if (redeliveryPolicy == null) { |
| return 0; |
| } |
| return redeliveryPolicy.getMaximumRedeliveries(); |
| } |
| |
| public boolean isUseExponentialBackOff() { |
| if (redeliveryPolicy == null) { |
| return false; |
| } |
| return redeliveryPolicy.isUseExponentialBackOff(); |
| } |
| |
| /** |
| * |
| */ |
| public void setBackOffMultiplier(double backOffMultiplier) { |
| lazyCreateRedeliveryPolicy().setBackOffMultiplier(backOffMultiplier); |
| } |
| |
| public long getMaximumRedeliveryDelay() { |
| if (redeliveryPolicy == null) { |
| return 0; |
| } |
| return redeliveryPolicy.getMaximumRedeliveryDelay(); |
| } |
| |
| public void setMaximumRedeliveryDelay(long maximumRedeliveryDelay) { |
| lazyCreateRedeliveryPolicy().setMaximumRedeliveryDelay(maximumRedeliveryDelay); |
| } |
| |
| /** |
| * |
| */ |
| public void setInitialRedeliveryDelay(long initialRedeliveryDelay) { |
| lazyCreateRedeliveryPolicy().setInitialRedeliveryDelay(initialRedeliveryDelay); |
| redeliveryPolicy.setRedeliveryDelay(initialRedeliveryDelay); |
| } |
| |
| /** |
| * |
| */ |
| public void setMaximumRedeliveries(int maximumRedeliveries) { |
| lazyCreateRedeliveryPolicy().setMaximumRedeliveries(maximumRedeliveries); |
| } |
| |
| /** |
| * |
| */ |
| public void setUseExponentialBackOff(boolean useExponentialBackOff) { |
| lazyCreateRedeliveryPolicy().setUseExponentialBackOff(useExponentialBackOff); |
| } |
| |
| // don't use getter to avoid causing introspection errors in containers |
| public RedeliveryPolicy redeliveryPolicy() { |
| return redeliveryPolicy; |
| } |
| |
| public RedeliveryPolicy lazyCreateRedeliveryPolicy() { |
| if (redeliveryPolicy == null) { |
| redeliveryPolicy = new RedeliveryPolicy(); |
| } |
| return redeliveryPolicy; |
| } |
| |
| public void setUseJndi(boolean useJndi) { |
| this.useJndi = useJndi; |
| } |
| |
| public boolean isUseJndi() { |
| return useJndi; |
| } |
| |
| public String getTrustStore() { |
| if (!isEmpty(trustStore)) { |
| return trustStore; |
| } |
| return null; |
| } |
| |
| public void setTrustStore(String trustStore) { |
| this.trustStore = trustStore; |
| } |
| |
| public String getTrustStorePassword() { |
| if (!isEmpty(trustStorePassword)) { |
| return trustStorePassword; |
| } |
| return null; |
| } |
| |
| public void setTrustStorePassword(String trustStorePassword) { |
| this.trustStorePassword = trustStorePassword; |
| } |
| |
| public String getKeyStore() { |
| if (!isEmpty(keyStore)) { |
| return keyStore; |
| } |
| return null; |
| } |
| |
| public void setKeyStore(String keyStore) { |
| this.keyStore = keyStore; |
| } |
| |
| public String getKeyStorePassword() { |
| if (!isEmpty(keyStorePassword)) { |
| return keyStorePassword; |
| } |
| return null; |
| } |
| |
| public void setKeyStorePassword(String keyStorePassword) { |
| this.keyStorePassword = keyStorePassword; |
| } |
| |
| public String getKeyStoreKeyPassword() { |
| if (!isEmpty(keyStoreKeyPassword)) { |
| return keyStoreKeyPassword; |
| } |
| return null; |
| } |
| |
| public void setKeyStoreKeyPassword(String keyStoreKeyPassword) { |
| this.keyStoreKeyPassword = keyStoreKeyPassword; |
| } |
| } |