1 /** 2 * All rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); 3 * you may not use this file except in compliance with the License. 4 * You may obtain a copy of the License at 5 * 6 * http://www.apache.org/licenses/LICENSE-2.0 7 * 8 * Unless required by applicable law or agreed to in writing, software 9 * distributed under the License is distributed on an "AS IS" BASIS, 10 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 * See the License for the specific language governing permissions and 12 * limitations under the License. 13 */ 14 package org.jivesoftware.smackx.pubsub; 15 16 import java.util.ArrayList; 17 import java.util.Iterator; 18 import java.util.List; 19 20 import org.jivesoftware.smackx.Form; 21 import org.jivesoftware.smackx.FormField; 22 import org.jivesoftware.smackx.packet.DataForm; 23 24 /** 25 * A decorator for a {@link Form} to easily enable reading and updating 26 * of node configuration. All operations read or update the underlying {@link DataForm}. 27 * 28 * <p>Unlike the {@link Form}.setAnswer(XXX)} methods, which throw an exception if the field does not 29 * exist, all <b>ConfigureForm.setXXX</b> methods will create the field in the wrapped form 30 * if it does not already exist. 31 * 32 * @author Robin Collier 33 */ 34 public class ConfigureForm extends Form 35 { 36 /** 37 * Create a decorator from an existing {@link DataForm} that has been 38 * retrieved from parsing a node configuration request. 39 * 40 * @param configDataForm 41 */ ConfigureForm(DataForm configDataForm)42 public ConfigureForm(DataForm configDataForm) 43 { 44 super(configDataForm); 45 } 46 47 /** 48 * Create a decorator from an existing {@link Form} for node configuration. 49 * Typically, this can be used to create a decorator for an answer form 50 * by using the result of {@link #createAnswerForm()} as the input parameter. 51 * 52 * @param nodeConfigForm 53 */ ConfigureForm(Form nodeConfigForm)54 public ConfigureForm(Form nodeConfigForm) 55 { 56 super(nodeConfigForm.getDataFormToSend()); 57 } 58 59 /** 60 * Create a new form for configuring a node. This would typically only be used 61 * when creating and configuring a node at the same time via {@link PubSubManager#createNode(String, Form)}, since 62 * configuration of an existing node is typically accomplished by calling {@link LeafNode#getNodeConfiguration()} and 63 * using the resulting form to create a answer form. See {@link #ConfigureForm(Form)}. 64 * @param formType 65 */ ConfigureForm(FormType formType)66 public ConfigureForm(FormType formType) 67 { 68 super(formType.toString()); 69 } 70 71 /** 72 * Get the currently configured {@link AccessModel}, null if it is not set. 73 * 74 * @return The current {@link AccessModel} 75 */ getAccessModel()76 public AccessModel getAccessModel() 77 { 78 String value = getFieldValue(ConfigureNodeFields.access_model); 79 80 if (value == null) 81 return null; 82 else 83 return AccessModel.valueOf(value); 84 } 85 86 /** 87 * Sets the value of access model. 88 * 89 * @param accessModel 90 */ setAccessModel(AccessModel accessModel)91 public void setAccessModel(AccessModel accessModel) 92 { 93 addField(ConfigureNodeFields.access_model, FormField.TYPE_LIST_SINGLE); 94 setAnswer(ConfigureNodeFields.access_model.getFieldName(), getListSingle(accessModel.toString())); 95 } 96 97 /** 98 * Returns the URL of an XSL transformation which can be applied to payloads in order to 99 * generate an appropriate message body element. 100 * 101 * @return URL to an XSL 102 */ getBodyXSLT()103 public String getBodyXSLT() 104 { 105 return getFieldValue(ConfigureNodeFields.body_xslt); 106 } 107 108 /** 109 * Set the URL of an XSL transformation which can be applied to payloads in order to 110 * generate an appropriate message body element. 111 * 112 * @param bodyXslt The URL of an XSL 113 */ setBodyXSLT(String bodyXslt)114 public void setBodyXSLT(String bodyXslt) 115 { 116 addField(ConfigureNodeFields.body_xslt, FormField.TYPE_TEXT_SINGLE); 117 setAnswer(ConfigureNodeFields.body_xslt.getFieldName(), bodyXslt); 118 } 119 120 /** 121 * The id's of the child nodes associated with a collection node (both leaf and collection). 122 * 123 * @return Iterator over the list of child nodes. 124 */ getChildren()125 public Iterator<String> getChildren() 126 { 127 return getFieldValues(ConfigureNodeFields.children); 128 } 129 130 /** 131 * Set the list of child node ids that are associated with a collection node. 132 * 133 * @param children 134 */ setChildren(List<String> children)135 public void setChildren(List<String> children) 136 { 137 addField(ConfigureNodeFields.children, FormField.TYPE_TEXT_MULTI); 138 setAnswer(ConfigureNodeFields.children.getFieldName(), children); 139 } 140 141 /** 142 * Returns the policy that determines who may associate children with the node. 143 * 144 * @return The current policy 145 */ getChildrenAssociationPolicy()146 public ChildrenAssociationPolicy getChildrenAssociationPolicy() 147 { 148 String value = getFieldValue(ConfigureNodeFields.children_association_policy); 149 150 if (value == null) 151 return null; 152 else 153 return ChildrenAssociationPolicy.valueOf(value); 154 } 155 156 /** 157 * Sets the policy that determines who may associate children with the node. 158 * 159 * @param policy The policy being set 160 */ setChildrenAssociationPolicy(ChildrenAssociationPolicy policy)161 public void setChildrenAssociationPolicy(ChildrenAssociationPolicy policy) 162 { 163 addField(ConfigureNodeFields.children_association_policy, FormField.TYPE_LIST_SINGLE); 164 List<String> values = new ArrayList<String>(1); 165 values.add(policy.toString()); 166 setAnswer(ConfigureNodeFields.children_association_policy.getFieldName(), values); 167 } 168 169 /** 170 * Iterator of JID's that are on the whitelist that determines who can associate child nodes 171 * with the collection node. This is only relevant if {@link #getChildrenAssociationPolicy()} is set to 172 * {@link ChildrenAssociationPolicy#whitelist}. 173 * 174 * @return Iterator over whitelist 175 */ getChildrenAssociationWhitelist()176 public Iterator<String> getChildrenAssociationWhitelist() 177 { 178 return getFieldValues(ConfigureNodeFields.children_association_whitelist); 179 } 180 181 /** 182 * Set the JID's in the whitelist of users that can associate child nodes with the collection 183 * node. This is only relevant if {@link #getChildrenAssociationPolicy()} is set to 184 * {@link ChildrenAssociationPolicy#whitelist}. 185 * 186 * @param whitelist The list of JID's 187 */ setChildrenAssociationWhitelist(List<String> whitelist)188 public void setChildrenAssociationWhitelist(List<String> whitelist) 189 { 190 addField(ConfigureNodeFields.children_association_whitelist, FormField.TYPE_JID_MULTI); 191 setAnswer(ConfigureNodeFields.children_association_whitelist.getFieldName(), whitelist); 192 } 193 194 /** 195 * Gets the maximum number of child nodes that can be associated with the collection node. 196 * 197 * @return The maximum number of child nodes 198 */ getChildrenMax()199 public int getChildrenMax() 200 { 201 return Integer.parseInt(getFieldValue(ConfigureNodeFields.children_max)); 202 } 203 204 /** 205 * Set the maximum number of child nodes that can be associated with a collection node. 206 * 207 * @param max The maximum number of child nodes. 208 */ setChildrenMax(int max)209 public void setChildrenMax(int max) 210 { 211 addField(ConfigureNodeFields.children_max, FormField.TYPE_TEXT_SINGLE); 212 setAnswer(ConfigureNodeFields.children_max.getFieldName(), max); 213 } 214 215 /** 216 * Gets the collection node which the node is affiliated with. 217 * 218 * @return The collection node id 219 */ getCollection()220 public String getCollection() 221 { 222 return getFieldValue(ConfigureNodeFields.collection); 223 } 224 225 /** 226 * Sets the collection node which the node is affiliated with. 227 * 228 * @param collection The node id of the collection node 229 */ setCollection(String collection)230 public void setCollection(String collection) 231 { 232 addField(ConfigureNodeFields.collection, FormField.TYPE_TEXT_SINGLE); 233 setAnswer(ConfigureNodeFields.collection.getFieldName(), collection); 234 } 235 236 /** 237 * Gets the URL of an XSL transformation which can be applied to the payload 238 * format in order to generate a valid Data Forms result that the client could 239 * display using a generic Data Forms rendering engine. 240 * 241 * @return The URL of an XSL transformation 242 */ getDataformXSLT()243 public String getDataformXSLT() 244 { 245 return getFieldValue(ConfigureNodeFields.dataform_xslt); 246 } 247 248 /** 249 * Sets the URL of an XSL transformation which can be applied to the payload 250 * format in order to generate a valid Data Forms result that the client could 251 * display using a generic Data Forms rendering engine. 252 * 253 * @param url The URL of an XSL transformation 254 */ setDataformXSLT(String url)255 public void setDataformXSLT(String url) 256 { 257 addField(ConfigureNodeFields.dataform_xslt, FormField.TYPE_TEXT_SINGLE); 258 setAnswer(ConfigureNodeFields.dataform_xslt.getFieldName(), url); 259 } 260 261 /** 262 * Does the node deliver payloads with event notifications. 263 * 264 * @return true if it does, false otherwise 265 */ isDeliverPayloads()266 public boolean isDeliverPayloads() 267 { 268 return parseBoolean(getFieldValue(ConfigureNodeFields.deliver_payloads)); 269 } 270 271 /** 272 * Sets whether the node will deliver payloads with event notifications. 273 * 274 * @param deliver true if the payload will be delivered, false otherwise 275 */ setDeliverPayloads(boolean deliver)276 public void setDeliverPayloads(boolean deliver) 277 { 278 addField(ConfigureNodeFields.deliver_payloads, FormField.TYPE_BOOLEAN); 279 setAnswer(ConfigureNodeFields.deliver_payloads.getFieldName(), deliver); 280 } 281 282 /** 283 * Determines who should get replies to items 284 * 285 * @return Who should get the reply 286 */ getItemReply()287 public ItemReply getItemReply() 288 { 289 String value = getFieldValue(ConfigureNodeFields.itemreply); 290 291 if (value == null) 292 return null; 293 else 294 return ItemReply.valueOf(value); 295 } 296 297 /** 298 * Sets who should get the replies to items 299 * 300 * @param reply Defines who should get the reply 301 */ setItemReply(ItemReply reply)302 public void setItemReply(ItemReply reply) 303 { 304 addField(ConfigureNodeFields.itemreply, FormField.TYPE_LIST_SINGLE); 305 setAnswer(ConfigureNodeFields.itemreply.getFieldName(), getListSingle(reply.toString())); 306 } 307 308 /** 309 * Gets the maximum number of items to persisted to this node if {@link #isPersistItems()} is 310 * true. 311 * 312 * @return The maximum number of items to persist 313 */ getMaxItems()314 public int getMaxItems() 315 { 316 return Integer.parseInt(getFieldValue(ConfigureNodeFields.max_items)); 317 } 318 319 /** 320 * Set the maximum number of items to persisted to this node if {@link #isPersistItems()} is 321 * true. 322 * 323 * @param max The maximum number of items to persist 324 */ setMaxItems(int max)325 public void setMaxItems(int max) 326 { 327 addField(ConfigureNodeFields.max_items, FormField.TYPE_TEXT_SINGLE); 328 setAnswer(ConfigureNodeFields.max_items.getFieldName(), max); 329 } 330 331 /** 332 * Gets the maximum payload size in bytes. 333 * 334 * @return The maximum payload size 335 */ getMaxPayloadSize()336 public int getMaxPayloadSize() 337 { 338 return Integer.parseInt(getFieldValue(ConfigureNodeFields.max_payload_size)); 339 } 340 341 /** 342 * Sets the maximum payload size in bytes 343 * 344 * @param max The maximum payload size 345 */ setMaxPayloadSize(int max)346 public void setMaxPayloadSize(int max) 347 { 348 addField(ConfigureNodeFields.max_payload_size, FormField.TYPE_TEXT_SINGLE); 349 setAnswer(ConfigureNodeFields.max_payload_size.getFieldName(), max); 350 } 351 352 /** 353 * Gets the node type 354 * 355 * @return The node type 356 */ getNodeType()357 public NodeType getNodeType() 358 { 359 String value = getFieldValue(ConfigureNodeFields.node_type); 360 361 if (value == null) 362 return null; 363 else 364 return NodeType.valueOf(value); 365 } 366 367 /** 368 * Sets the node type 369 * 370 * @param type The node type 371 */ setNodeType(NodeType type)372 public void setNodeType(NodeType type) 373 { 374 addField(ConfigureNodeFields.node_type, FormField.TYPE_LIST_SINGLE); 375 setAnswer(ConfigureNodeFields.node_type.getFieldName(), getListSingle(type.toString())); 376 } 377 378 /** 379 * Determines if subscribers should be notified when the configuration changes. 380 * 381 * @return true if they should be notified, false otherwise 382 */ isNotifyConfig()383 public boolean isNotifyConfig() 384 { 385 return parseBoolean(getFieldValue(ConfigureNodeFields.notify_config)); 386 } 387 388 /** 389 * Sets whether subscribers should be notified when the configuration changes. 390 * 391 * @param notify true if subscribers should be notified, false otherwise 392 */ setNotifyConfig(boolean notify)393 public void setNotifyConfig(boolean notify) 394 { 395 addField(ConfigureNodeFields.notify_config, FormField.TYPE_BOOLEAN); 396 setAnswer(ConfigureNodeFields.notify_config.getFieldName(), notify); 397 } 398 399 /** 400 * Determines whether subscribers should be notified when the node is deleted. 401 * 402 * @return true if subscribers should be notified, false otherwise 403 */ isNotifyDelete()404 public boolean isNotifyDelete() 405 { 406 return parseBoolean(getFieldValue(ConfigureNodeFields.notify_delete)); 407 } 408 409 /** 410 * Sets whether subscribers should be notified when the node is deleted. 411 * 412 * @param notify true if subscribers should be notified, false otherwise 413 */ setNotifyDelete(boolean notify)414 public void setNotifyDelete(boolean notify) 415 { 416 addField(ConfigureNodeFields.notify_delete, FormField.TYPE_BOOLEAN); 417 setAnswer(ConfigureNodeFields.notify_delete.getFieldName(), notify); 418 } 419 420 /** 421 * Determines whether subscribers should be notified when items are deleted 422 * from the node. 423 * 424 * @return true if subscribers should be notified, false otherwise 425 */ isNotifyRetract()426 public boolean isNotifyRetract() 427 { 428 return parseBoolean(getFieldValue(ConfigureNodeFields.notify_retract)); 429 } 430 431 /** 432 * Sets whether subscribers should be notified when items are deleted 433 * from the node. 434 * 435 * @param notify true if subscribers should be notified, false otherwise 436 */ setNotifyRetract(boolean notify)437 public void setNotifyRetract(boolean notify) 438 { 439 addField(ConfigureNodeFields.notify_retract, FormField.TYPE_BOOLEAN); 440 setAnswer(ConfigureNodeFields.notify_retract.getFieldName(), notify); 441 } 442 443 /** 444 * Determines whether items should be persisted in the node. 445 * 446 * @return true if items are persisted 447 */ isPersistItems()448 public boolean isPersistItems() 449 { 450 return parseBoolean(getFieldValue(ConfigureNodeFields.persist_items)); 451 } 452 453 /** 454 * Sets whether items should be persisted in the node. 455 * 456 * @param persist true if items should be persisted, false otherwise 457 */ setPersistentItems(boolean persist)458 public void setPersistentItems(boolean persist) 459 { 460 addField(ConfigureNodeFields.persist_items, FormField.TYPE_BOOLEAN); 461 setAnswer(ConfigureNodeFields.persist_items.getFieldName(), persist); 462 } 463 464 /** 465 * Determines whether to deliver notifications to available users only. 466 * 467 * @return true if users must be available 468 */ isPresenceBasedDelivery()469 public boolean isPresenceBasedDelivery() 470 { 471 return parseBoolean(getFieldValue(ConfigureNodeFields.presence_based_delivery)); 472 } 473 474 /** 475 * Sets whether to deliver notifications to available users only. 476 * 477 * @param presenceBased true if user must be available, false otherwise 478 */ setPresenceBasedDelivery(boolean presenceBased)479 public void setPresenceBasedDelivery(boolean presenceBased) 480 { 481 addField(ConfigureNodeFields.presence_based_delivery, FormField.TYPE_BOOLEAN); 482 setAnswer(ConfigureNodeFields.presence_based_delivery.getFieldName(), presenceBased); 483 } 484 485 /** 486 * Gets the publishing model for the node, which determines who may publish to it. 487 * 488 * @return The publishing model 489 */ getPublishModel()490 public PublishModel getPublishModel() 491 { 492 String value = getFieldValue(ConfigureNodeFields.publish_model); 493 494 if (value == null) 495 return null; 496 else 497 return PublishModel.valueOf(value); 498 } 499 500 /** 501 * Sets the publishing model for the node, which determines who may publish to it. 502 * 503 * @param publish The enum representing the possible options for the publishing model 504 */ setPublishModel(PublishModel publish)505 public void setPublishModel(PublishModel publish) 506 { 507 addField(ConfigureNodeFields.publish_model, FormField.TYPE_LIST_SINGLE); 508 setAnswer(ConfigureNodeFields.publish_model.getFieldName(), getListSingle(publish.toString())); 509 } 510 511 /** 512 * Iterator over the multi user chat rooms that are specified as reply rooms. 513 * 514 * @return The reply room JID's 515 */ getReplyRoom()516 public Iterator<String> getReplyRoom() 517 { 518 return getFieldValues(ConfigureNodeFields.replyroom); 519 } 520 521 /** 522 * Sets the multi user chat rooms that are specified as reply rooms. 523 * 524 * @param replyRooms The multi user chat room to use as reply rooms 525 */ setReplyRoom(List<String> replyRooms)526 public void setReplyRoom(List<String> replyRooms) 527 { 528 addField(ConfigureNodeFields.replyroom, FormField.TYPE_LIST_MULTI); 529 setAnswer(ConfigureNodeFields.replyroom.getFieldName(), replyRooms); 530 } 531 532 /** 533 * Gets the specific JID's for reply to. 534 * 535 * @return The JID's 536 */ getReplyTo()537 public Iterator<String> getReplyTo() 538 { 539 return getFieldValues(ConfigureNodeFields.replyto); 540 } 541 542 /** 543 * Sets the specific JID's for reply to. 544 * 545 * @param replyTos The JID's to reply to 546 */ setReplyTo(List<String> replyTos)547 public void setReplyTo(List<String> replyTos) 548 { 549 addField(ConfigureNodeFields.replyto, FormField.TYPE_LIST_MULTI); 550 setAnswer(ConfigureNodeFields.replyto.getFieldName(), replyTos); 551 } 552 553 /** 554 * Gets the roster groups that are allowed to subscribe and retrieve items. 555 * 556 * @return The roster groups 557 */ getRosterGroupsAllowed()558 public Iterator<String> getRosterGroupsAllowed() 559 { 560 return getFieldValues(ConfigureNodeFields.roster_groups_allowed); 561 } 562 563 /** 564 * Sets the roster groups that are allowed to subscribe and retrieve items. 565 * 566 * @param groups The roster groups 567 */ setRosterGroupsAllowed(List<String> groups)568 public void setRosterGroupsAllowed(List<String> groups) 569 { 570 addField(ConfigureNodeFields.roster_groups_allowed, FormField.TYPE_LIST_MULTI); 571 setAnswer(ConfigureNodeFields.roster_groups_allowed.getFieldName(), groups); 572 } 573 574 /** 575 * Determines if subscriptions are allowed. 576 * 577 * @return true if subscriptions are allowed, false otherwise 578 */ isSubscibe()579 public boolean isSubscibe() 580 { 581 return parseBoolean(getFieldValue(ConfigureNodeFields.subscribe)); 582 } 583 584 /** 585 * Sets whether subscriptions are allowed. 586 * 587 * @param subscribe true if they are, false otherwise 588 */ setSubscribe(boolean subscribe)589 public void setSubscribe(boolean subscribe) 590 { 591 addField(ConfigureNodeFields.subscribe, FormField.TYPE_BOOLEAN); 592 setAnswer(ConfigureNodeFields.subscribe.getFieldName(), subscribe); 593 } 594 595 /** 596 * Gets the human readable node title. 597 * 598 * @return The node title 599 */ getTitle()600 public String getTitle() 601 { 602 return getFieldValue(ConfigureNodeFields.title); 603 } 604 605 /** 606 * Sets a human readable title for the node. 607 * 608 * @param title The node title 609 */ setTitle(String title)610 public void setTitle(String title) 611 { 612 addField(ConfigureNodeFields.title, FormField.TYPE_TEXT_SINGLE); 613 setAnswer(ConfigureNodeFields.title.getFieldName(), title); 614 } 615 616 /** 617 * The type of node data, usually specified by the namespace of the payload (if any). 618 * 619 * @return The type of node data 620 */ getDataType()621 public String getDataType() 622 { 623 return getFieldValue(ConfigureNodeFields.type); 624 } 625 626 /** 627 * Sets the type of node data, usually specified by the namespace of the payload (if any). 628 * 629 * @param type The type of node data 630 */ setDataType(String type)631 public void setDataType(String type) 632 { 633 addField(ConfigureNodeFields.type, FormField.TYPE_TEXT_SINGLE); 634 setAnswer(ConfigureNodeFields.type.getFieldName(), type); 635 } 636 637 @Override toString()638 public String toString() 639 { 640 StringBuilder result = new StringBuilder(getClass().getName() + " Content ["); 641 642 Iterator<FormField> fields = getFields(); 643 644 while (fields.hasNext()) 645 { 646 FormField formField = fields.next(); 647 result.append('('); 648 result.append(formField.getVariable()); 649 result.append(':'); 650 651 Iterator<String> values = formField.getValues(); 652 StringBuilder valuesBuilder = new StringBuilder(); 653 654 while (values.hasNext()) 655 { 656 if (valuesBuilder.length() > 0) 657 result.append(','); 658 String value = (String)values.next(); 659 valuesBuilder.append(value); 660 } 661 662 if (valuesBuilder.length() == 0) 663 valuesBuilder.append("NOT SET"); 664 result.append(valuesBuilder); 665 result.append(')'); 666 } 667 result.append(']'); 668 return result.toString(); 669 } 670 parseBoolean(String fieldValue)671 static private boolean parseBoolean(String fieldValue) 672 { 673 return ("1".equals(fieldValue) || "true".equals(fieldValue)); 674 } 675 getFieldValue(ConfigureNodeFields field)676 private String getFieldValue(ConfigureNodeFields field) 677 { 678 FormField formField = getField(field.getFieldName()); 679 680 return (formField.getValues().hasNext()) ? formField.getValues().next() : null; 681 } 682 getFieldValues(ConfigureNodeFields field)683 private Iterator<String> getFieldValues(ConfigureNodeFields field) 684 { 685 FormField formField = getField(field.getFieldName()); 686 687 return formField.getValues(); 688 } 689 addField(ConfigureNodeFields nodeField, String type)690 private void addField(ConfigureNodeFields nodeField, String type) 691 { 692 String fieldName = nodeField.getFieldName(); 693 694 if (getField(fieldName) == null) 695 { 696 FormField field = new FormField(fieldName); 697 field.setType(type); 698 addField(field); 699 } 700 } 701 getListSingle(String value)702 private List<String> getListSingle(String value) 703 { 704 List<String> list = new ArrayList<String>(1); 705 list.add(value); 706 return list; 707 } 708 709 } 710