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 }