001    /**
002     *
003     * Copyright 2004 Hiram Chirino
004     * Licensed under the Apache License, Version 2.0 (the "License");
005     *
006     * you may not use this file except in compliance with the License.
007     * You may obtain a copy of the License at
008     *
009     * http://www.apache.org/licenses/LICENSE-2.0
010     *
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS,
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     * See the License for the specific language governing permissions and
015     * limitations under the License.
016     *
017     **/
018    package org.activemq.ra;
019    
020    import java.beans.IntrospectionException;
021    import java.beans.PropertyDescriptor;
022    import java.util.ArrayList;
023    import java.util.Iterator;
024    import java.util.List;
025    
026    import javax.jms.Queue;
027    import javax.jms.Session;
028    import javax.jms.Topic;
029    import javax.resource.ResourceException;
030    import javax.resource.spi.ActivationSpec;
031    import javax.resource.spi.InvalidPropertyException;
032    import javax.resource.spi.ResourceAdapter;
033    
034    import org.activemq.message.ActiveMQDestination;
035    import org.activemq.message.ActiveMQQueue;
036    import org.activemq.message.ActiveMQTopic;
037    import org.activemq.selector.SelectorParser;
038    
039    /**
040     * @version $Revision: 1.1.1.1 $ $Date: 2005/03/11 21:15:09 $
041     */
042    public class ActiveMQActivationSpec implements ActivationSpec {
043    
044        /** Auto-acknowledge constant for <code>acknowledgeMode</code> property **/
045        public static final String AUTO_ACKNOWLEDGE_MODE = "Auto-acknowledge";
046        /** Dups-ok-acknowledge constant for <code>acknowledgeMode</code> property * */
047        public static final String DUPS_OK_ACKNOWLEDGE_MODE = "Dups-ok-acknowledge";    
048        /** Durable constant for <code>subscriptionDurability</code> property * */
049        public static final String DURABLE_SUBSCRIPTION = "Durable";
050        /** NonDurable constant for <code>subscriptionDurability</code> property * */
051        public static final String NON_DURABLE_SUBSCRIPTION = "NonDurable";
052        
053        public static final int INVALID_ACKNOWLEDGE_MODE = -1;
054        
055        private ActiveMQResourceAdapter resourceAdapter;
056        private String destinationType;
057        private String messageSelector;
058        private String destination;
059        private String acknowledgeMode = AUTO_ACKNOWLEDGE_MODE;
060        private String userName;
061        private String password;
062        private String clientId;
063        private String subscriptionName;
064        private String subscriptionDurability = NON_DURABLE_SUBSCRIPTION;    
065        private String noLocal = "false";
066        private String useRAManagedTransaction = "false";
067        private String maxSessions="10";
068        private String maxMessagesPerSessions="10";
069        private String enableBatch = "false";
070        private String maxMessagesPerBatch = "10";    
071        
072        /**
073         * @see javax.resource.spi.ActivationSpec#validate()
074         */
075        public void validate() throws InvalidPropertyException {
076            List errorMessages = new ArrayList();
077            List propsNotSet = new ArrayList();
078            try {
079                if (!isValidDestination(errorMessages))
080                    propsNotSet.add(new PropertyDescriptor("destination", ActiveMQActivationSpec.class));
081                if (!isValidDestinationType(errorMessages))
082                    propsNotSet.add(new PropertyDescriptor("destinationType", ActiveMQActivationSpec.class));
083                if (!isValidAcknowledgeMode(errorMessages))
084                    propsNotSet.add(new PropertyDescriptor("acknowledgeMode", ActiveMQActivationSpec.class));
085                if (!isValidSubscriptionDurability(errorMessages))
086                    propsNotSet.add(new PropertyDescriptor("subscriptionDurability", ActiveMQActivationSpec.class));
087                if (!isValidClientId(errorMessages))
088                    propsNotSet.add(new PropertyDescriptor("clientId", ActiveMQActivationSpec.class));
089                if (!isValidSubscriptionName(errorMessages))
090                    propsNotSet.add(new PropertyDescriptor("subscriptionName", ActiveMQActivationSpec.class));
091                if (!isValidMaxMessagesPerSessions(errorMessages))
092                    propsNotSet.add(new PropertyDescriptor("maxMessagesPerSessions", ActiveMQActivationSpec.class));
093                if (!isValidMaxSessions(errorMessages))
094                    propsNotSet.add(new PropertyDescriptor("maxSessions", ActiveMQActivationSpec.class));
095                if (!isValidMessageSelector(errorMessages))
096                    propsNotSet.add(new PropertyDescriptor("messageSelector", ActiveMQActivationSpec.class));
097                if (!isValidNoLocal(errorMessages))
098                    propsNotSet.add(new PropertyDescriptor("noLocal", ActiveMQActivationSpec.class));
099                if (!isValidUseRAManagedTransaction(errorMessages))
100                    propsNotSet.add(new PropertyDescriptor("useRAManagedTransaction", ActiveMQActivationSpec.class));
101                if (!isValidEnableBatch(errorMessages))
102                    propsNotSet.add(new PropertyDescriptor("enableBatch", ActiveMQActivationSpec.class));
103                if (!isValidMaxMessagesPerBatch(errorMessages))
104                    propsNotSet.add(new PropertyDescriptor("maxMessagesPerBatch", ActiveMQActivationSpec.class));
105                
106            } catch (IntrospectionException e) {
107                e.printStackTrace();
108            }
109            
110            if (propsNotSet.size() > 0) {
111                StringBuffer b = new StringBuffer();
112                b.append("Invalid settings:");
113                for (Iterator iter = errorMessages.iterator(); iter.hasNext();) {
114                    b.append(" ");
115                    b.append(iter.next());
116                }
117                InvalidPropertyException e = new InvalidPropertyException(b.toString());
118                final PropertyDescriptor[] descriptors = (PropertyDescriptor[]) propsNotSet.toArray(new PropertyDescriptor[propsNotSet.size()]);
119                e.setInvalidPropertyDescriptors(descriptors);
120                throw e;
121            }
122        }
123    
124        private boolean isValidUseRAManagedTransaction(List errorMessages) {
125            try {
126                new Boolean(noLocal);
127                return true;
128            } catch (Throwable e) {
129            }
130            errorMessages.add("noLocal must be set to: true or false.");
131            return false;
132        }
133    
134        private boolean isValidNoLocal(List errorMessages) {
135            try {
136                new Boolean(noLocal);
137                return true;
138            } catch (Throwable e) {
139            }
140            errorMessages.add("noLocal must be set to: true or false.");
141            return false;
142        }
143    
144        private boolean isValidMessageSelector(List errorMessages) {
145            try {
146                if( !isEmpty(messageSelector) ) {
147                    new SelectorParser().parse(messageSelector);
148                }
149                return true;
150            } catch (Throwable e) {
151                errorMessages.add("messageSelector not set to valid message selector: "+e.getMessage());
152                return false;
153            }
154        }
155    
156        private boolean isValidMaxSessions(List errorMessages) {
157            try {
158                if( Integer.parseInt(maxSessions) > 0 ) {
159                    return true;
160                }
161            } catch (NumberFormatException e) {
162            }
163            errorMessages.add("maxSessions must be set to number > 0");
164            return false;
165        }
166    
167        private boolean isValidMaxMessagesPerSessions(List errorMessages) {
168            try {
169                if( Integer.parseInt(maxMessagesPerSessions) > 0 ) {
170                    return true;
171                }
172            } catch (NumberFormatException e) {
173            }
174            errorMessages.add("maxMessagesPerSessions must be set to number > 0");
175            return false;
176        }
177    
178        private boolean isValidMaxMessagesPerBatch(List errorMessages) {
179            try {
180                if( Integer.parseInt(maxMessagesPerBatch) > 0 ) {
181                    return true;
182                }
183            } catch (NumberFormatException e) {
184            }
185            errorMessages.add("maxMessagesPerBatch must be set to number > 0");
186            return false;
187        }
188    
189        private boolean isValidEnableBatch(List errorMessages) {
190            try {
191                new Boolean(enableBatch);
192                return true;
193            } catch (Throwable e) {
194            }
195            errorMessages.add("enableBatch must be set to: true or false");
196            return false;
197        }
198    
199        /**
200         * @see javax.resource.spi.ResourceAdapterAssociation#getResourceAdapter()
201         */
202        public ResourceAdapter getResourceAdapter() {
203            return resourceAdapter;
204        }
205    
206        /**
207         * @see javax.resource.spi.ResourceAdapterAssociation#setResourceAdapter(javax.resource.spi.ResourceAdapter)
208         */
209        public void setResourceAdapter(ResourceAdapter resourceAdapter) throws ResourceException {
210            //spec section 5.3.3
211            if (this.resourceAdapter != null) {
212                throw new ResourceException("ResourceAdapter already set");
213            }
214            if (!(resourceAdapter instanceof ActiveMQResourceAdapter)) {
215                throw new ResourceException("ResourceAdapter is not of type: " + ActiveMQResourceAdapter.class.getName());
216            }
217            this.resourceAdapter = (ActiveMQResourceAdapter) resourceAdapter;
218        }
219    
220    
221        /////////////////////////////////////////////////////////////////////////
222        //
223        // Java Bean getters and setters for this ActivationSpec class.
224        //
225        /////////////////////////////////////////////////////////////////////////
226        /**
227         * @return Returns the destinationType.
228         */
229        public String getDestinationType() {
230            if (!isEmpty(destinationType)) {
231                return destinationType;
232            }
233            return null;
234        }
235    
236        /**
237         * @param destinationType The destinationType to set.
238         */
239        public void setDestinationType(String destinationType) {
240            this.destinationType = destinationType;
241        }
242        
243        public String getPassword() {
244            if (!isEmpty(password)) {                
245                return password;
246            }
247            return null;
248        }
249        
250        public void setPassword(String password) {
251            this.password = password;
252        }
253    
254        public String getUserName() {
255            if (!isEmpty(userName)) {        
256                return userName;
257            }
258            return null;
259        }
260        
261        public void setUserName(String userName) {
262            this.userName = userName;
263        }
264        
265        /**
266         * @return Returns the messageSelector.
267         */
268        public String getMessageSelector() {
269            if (!isEmpty(messageSelector)) {
270                return messageSelector;
271            }
272            return null;
273        }
274    
275        /**
276         * @param messageSelector The messageSelector to set.
277         */
278        public void setMessageSelector(String messageSelector) {
279            this.messageSelector = messageSelector;
280        }
281    
282        /**
283         * @return Returns the noLocal.
284         */
285        public String getNoLocal() {
286            return noLocal;
287        }
288    
289        /**
290         * @param noLocal The noLocal to set.
291         */
292        public void setNoLocal(String noLocal) {
293            if( noLocal!=null ) {
294                this.noLocal = noLocal;
295            }
296        }
297    
298        public String getAcknowledgeMode() {
299            if (!isEmpty(acknowledgeMode)) {
300                return acknowledgeMode;
301            }
302            return null;
303        }
304    
305        public void setAcknowledgeMode(String acknowledgeMode) {
306            this.acknowledgeMode = acknowledgeMode;
307        }
308        
309        public String getClientId() {
310            if (!isEmpty(clientId)) {
311                return clientId;
312            }
313            return null;
314        }
315    
316        public void setClientId(String clientId) {        
317            this.clientId = clientId;            
318        }
319    
320        public String getDestination() {
321            if (!isEmpty(destination)) {
322                return destination;
323            }
324            return null;
325        }
326    
327        public void setDestination(String destination) {
328            this.destination = destination;
329        }
330    
331        public String getSubscriptionDurability() {
332            if (!isEmpty(subscriptionDurability)) {                
333                return subscriptionDurability;
334            }
335            return null;
336        }
337    
338        public void setSubscriptionDurability(String subscriptionDurability) {
339            this.subscriptionDurability = subscriptionDurability;
340        }
341    
342        public String getSubscriptionName() {
343            if (!isEmpty(subscriptionName)) {
344                return subscriptionName;
345            }
346            return null;
347        }
348    
349        public void setSubscriptionName(String subscriptionName) {
350            this.subscriptionName = subscriptionName;
351        }
352        
353        private boolean isValidSubscriptionName(List errorMessages) {
354            if( !isDurableSubscription() ? true : subscriptionName != null && subscriptionName.trim().length() > 0 ) {
355                return true;
356            } 
357            errorMessages.add("subscriptionName must be set since durable subscription was requested.");
358            return false;
359        }
360    
361        private boolean isValidClientId(List errorMessages) {
362            if( !isDurableSubscription() ? true : clientId != null && clientId.trim().length() > 0 ) {
363                return true;
364            }
365            errorMessages.add("clientId must be set since durable subscription was requested.");
366            return false;
367        }
368    
369        public boolean isDurableSubscription() {
370            return DURABLE_SUBSCRIPTION.equals(subscriptionDurability);
371        }
372    
373        private boolean isValidSubscriptionDurability(List errorMessages) {
374            // subscriptionDurability only applies to Topics
375            if ( DURABLE_SUBSCRIPTION.equals(subscriptionDurability) &&
376                 getDestinationType() != null && !Topic.class.getName().equals(getDestinationType())) {
377                errorMessages.add("subscriptionDurability cannot be set to: "+DURABLE_SUBSCRIPTION+" when destinationType is set to "+
378                    Queue.class.getName()+" as it is only valid when destinationType is set to "+Topic.class.getName()+".");
379                return false;
380            }
381            if (NON_DURABLE_SUBSCRIPTION.equals(subscriptionDurability) || DURABLE_SUBSCRIPTION.equals(subscriptionDurability))
382                return true;
383            errorMessages.add("subscriptionDurability must be set to: "+NON_DURABLE_SUBSCRIPTION+" or "+DURABLE_SUBSCRIPTION+".");
384            return false;
385        }
386    
387        private boolean isValidAcknowledgeMode(List errorMessages) {
388            if (AUTO_ACKNOWLEDGE_MODE.equals(acknowledgeMode) || DUPS_OK_ACKNOWLEDGE_MODE.equals(acknowledgeMode))
389                return true;
390            errorMessages.add("acknowledgeMode must be set to: "+AUTO_ACKNOWLEDGE_MODE+" or "+DUPS_OK_ACKNOWLEDGE_MODE+".");
391            return false;
392        }
393    
394        private boolean isValidDestinationType(List errorMessages) {
395            if (Queue.class.getName().equals(destinationType) || Topic.class.getName().equals(destinationType))
396                return true;
397            errorMessages.add("destinationType must be set to: "+Queue.class.getName()+" or "+Topic.class.getName()+".");
398            return false;
399        }
400    
401        private boolean isValidDestination(List errorMessages) {
402            if(!(destination == null || destination.equals(""))) 
403                return true;
404            errorMessages.add("destination is a required field and must be set to the destination name.");
405            return false;
406        }
407         
408        private boolean isEmpty(String value) {
409            return value == null || "".equals(value.trim());
410        }
411    
412       public String toString() {
413            return "ActiveMQActivationSpec{" +
414                    "acknowledgeMode='" + acknowledgeMode + "'" +
415                    ", destinationType='" + destinationType + "'" +
416                    ", messageSelector='" + messageSelector + "'" +
417                    ", destination='" + destination + "'" +
418                    ", clientId='" + clientId + "'" +
419                    ", subscriptionName='" + subscriptionName + "'" +
420                    ", subscriptionDurability='" + subscriptionDurability + "'" +
421                    "}";
422        }
423    
424        public int getAcknowledgeModeForSession() { 
425            if( AUTO_ACKNOWLEDGE_MODE.equals(acknowledgeMode) ) {
426                return Session.AUTO_ACKNOWLEDGE;
427            } else if( DUPS_OK_ACKNOWLEDGE_MODE.equals(acknowledgeMode) ) {
428                return Session.DUPS_OK_ACKNOWLEDGE;
429            } else {
430                return INVALID_ACKNOWLEDGE_MODE;
431            }
432        }
433    
434        public ActiveMQDestination createDestination() {
435            if( isEmpty(destinationType) || isEmpty(destination) )
436                return null;
437            
438            ActiveMQDestination dest = null;
439            if (Queue.class.getName().equals(destinationType)) {
440                dest = new ActiveMQQueue(destination);
441            } else if (Topic.class.getName().equals(destinationType)) {
442                dest = new ActiveMQTopic(destination);
443            } else {
444                assert false : "Execution should never reach here";
445            }
446            return dest;
447        }
448    
449        public String getMaxMessagesPerSessions() {
450            return maxMessagesPerSessions.toString();
451        }
452        
453        public void setMaxMessagesPerSessions(String maxMessagesPerSessions) {
454            if( maxMessagesPerSessions!=null ) {
455                this.maxMessagesPerSessions = maxMessagesPerSessions;
456            }
457        }
458        
459    
460        public String getMaxSessions() {
461            return maxSessions;
462        }
463        public void setMaxSessions(String maxSessions) {
464            if( maxSessions!=null ) {
465                this.maxSessions = maxSessions;
466            }
467        }
468        
469        public String getUseRAManagedTransaction() {
470            return useRAManagedTransaction;
471        }
472        
473        public void setUseRAManagedTransaction(String useRAManagedTransaction) {
474            if( useRAManagedTransaction!=null ) {
475                this.useRAManagedTransaction = useRAManagedTransaction;
476            }
477        }
478    
479        public int getMaxMessagesPerSessionsIntValue() {
480            return Integer.parseInt(maxMessagesPerSessions);
481        }
482    
483        public int getMaxSessionsIntValue() {
484            return Integer.parseInt(maxSessions);
485        }
486    
487        public boolean isUseRAManagedTransactionEnabled() {
488            return new Boolean(useRAManagedTransaction).booleanValue();
489        }
490    
491        public boolean getNoLocalBooleanValue() {
492            return new Boolean(noLocal).booleanValue();
493        }
494    
495        public String getEnableBatch() {
496            return enableBatch;
497        }
498        
499        public void setEnableBatch(String enableBatch) {
500            if (enableBatch != null) {
501                    this.enableBatch = enableBatch;
502            }
503        }
504        
505        public boolean getEnableBatchBooleanValue() {
506            return new Boolean(enableBatch).booleanValue();
507        }
508    
509        public int getMaxMessagesPerBatchIntValue() {
510            return Integer.parseInt(maxMessagesPerBatch);
511        }
512    
513        public String getMaxMessagesPerBatch() {
514            return maxMessagesPerBatch.toString();
515        }
516        
517        public void setMaxMessagesPerBatch(String maxMessagesPerBatch) {
518            if (maxMessagesPerBatch != null) {
519                this.maxMessagesPerBatch = maxMessagesPerBatch;
520            }
521        }
522        
523    }