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 }