001/** 002 * 003 * Copyright the original author or authors 004 * 005 * Licensed under the Apache License, Version 2.0 (the "License"); 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 */ 017package org.jivesoftware.smackx.pubsub; 018 019import java.util.ArrayList; 020import java.util.List; 021 022import org.jivesoftware.smackx.xdata.Form; 023import org.jivesoftware.smackx.xdata.FormField; 024import org.jivesoftware.smackx.xdata.packet.DataForm; 025 026/** 027 * A decorator for a {@link Form} to easily enable reading and updating 028 * of node configuration. All operations read or update the underlying {@link DataForm}. 029 * 030 * <p>Unlike the {@link Form}.setAnswer(XXX)} methods, which throw an exception if the field does not 031 * exist, all <b>ConfigureForm.setXXX</b> methods will create the field in the wrapped form 032 * if it does not already exist. 033 * 034 * @author Robin Collier 035 */ 036public class ConfigureForm extends Form { 037 /** 038 * Create a decorator from an existing {@link DataForm} that has been 039 * retrieved from parsing a node configuration request. 040 * 041 * @param configDataForm 042 */ 043 public ConfigureForm(DataForm configDataForm) { 044 super(configDataForm); 045 } 046 047 /** 048 * Create a decorator from an existing {@link Form} for node configuration. 049 * Typically, this can be used to create a decorator for an answer form 050 * by using the result of {@link #createAnswerForm()} as the input parameter. 051 * 052 * @param nodeConfigForm 053 */ 054 public ConfigureForm(Form nodeConfigForm) { 055 super(nodeConfigForm.getDataFormToSend()); 056 } 057 058 /** 059 * Create a new form for configuring a node. This would typically only be used 060 * when creating and configuring a node at the same time via {@link PubSubManager#createNode(String, Form)}, since 061 * configuration of an existing node is typically accomplished by calling {@link LeafNode#getNodeConfiguration()} and 062 * using the resulting form to create a answer form. See {@link #ConfigureForm(Form)}. 063 * @param formType 064 */ 065 public ConfigureForm(DataForm.Type formType) { 066 super(formType); 067 } 068 069 /** 070 * Get the currently configured {@link AccessModel}, null if it is not set. 071 * 072 * @return The current {@link AccessModel} 073 */ 074 public AccessModel getAccessModel() { 075 String value = getFieldValue(ConfigureNodeFields.access_model); 076 077 if (value == null) 078 return null; 079 else 080 return AccessModel.valueOf(value); 081 } 082 083 /** 084 * Sets the value of access model. 085 * 086 * @param accessModel 087 */ 088 public void setAccessModel(AccessModel accessModel) { 089 addField(ConfigureNodeFields.access_model, FormField.Type.list_single); 090 setAnswer(ConfigureNodeFields.access_model.getFieldName(), getListSingle(accessModel.toString())); 091 } 092 093 /** 094 * Returns the URL of an XSL transformation which can be applied to payloads in order to 095 * generate an appropriate message body element. 096 * 097 * @return URL to an XSL 098 */ 099 public String getBodyXSLT() { 100 return getFieldValue(ConfigureNodeFields.body_xslt); 101 } 102 103 /** 104 * Set the URL of an XSL transformation which can be applied to payloads in order to 105 * generate an appropriate message body element. 106 * 107 * @param bodyXslt The URL of an XSL 108 */ 109 public void setBodyXSLT(String bodyXslt) { 110 addField(ConfigureNodeFields.body_xslt, FormField.Type.text_single); 111 setAnswer(ConfigureNodeFields.body_xslt.getFieldName(), bodyXslt); 112 } 113 114 /** 115 * The id's of the child nodes associated with a collection node (both leaf and collection). 116 * 117 * @return list of child nodes. 118 */ 119 public List<String> getChildren() { 120 return getFieldValues(ConfigureNodeFields.children); 121 } 122 123 /** 124 * Set the list of child node ids that are associated with a collection node. 125 * 126 * @param children 127 */ 128 public void setChildren(List<String> children) { 129 addField(ConfigureNodeFields.children, FormField.Type.text_multi); 130 setAnswer(ConfigureNodeFields.children.getFieldName(), children); 131 } 132 133 /** 134 * Returns the policy that determines who may associate children with the node. 135 * 136 * @return The current policy 137 */ 138 public ChildrenAssociationPolicy getChildrenAssociationPolicy() { 139 String value = getFieldValue(ConfigureNodeFields.children_association_policy); 140 141 if (value == null) 142 return null; 143 else 144 return ChildrenAssociationPolicy.valueOf(value); 145 } 146 147 /** 148 * Sets the policy that determines who may associate children with the node. 149 * 150 * @param policy The policy being set 151 */ 152 public void setChildrenAssociationPolicy(ChildrenAssociationPolicy policy) { 153 addField(ConfigureNodeFields.children_association_policy, FormField.Type.list_single); 154 List<String> values = new ArrayList<>(1); 155 values.add(policy.toString()); 156 setAnswer(ConfigureNodeFields.children_association_policy.getFieldName(), values); 157 } 158 159 /** 160 * List of JID's that are on the whitelist that determines who can associate child nodes 161 * with the collection node. This is only relevant if {@link #getChildrenAssociationPolicy()} is set to 162 * {@link ChildrenAssociationPolicy#whitelist}. 163 * 164 * @return List of the whitelist 165 */ 166 public List<String> getChildrenAssociationWhitelist() { 167 return getFieldValues(ConfigureNodeFields.children_association_whitelist); 168 } 169 170 /** 171 * Set the JID's in the whitelist of users that can associate child nodes with the collection 172 * node. This is only relevant if {@link #getChildrenAssociationPolicy()} is set to 173 * {@link ChildrenAssociationPolicy#whitelist}. 174 * 175 * @param whitelist The list of JID's 176 */ 177 public void setChildrenAssociationWhitelist(List<String> whitelist) { 178 addField(ConfigureNodeFields.children_association_whitelist, FormField.Type.jid_multi); 179 setAnswer(ConfigureNodeFields.children_association_whitelist.getFieldName(), whitelist); 180 } 181 182 /** 183 * Gets the maximum number of child nodes that can be associated with the collection node. 184 * 185 * @return The maximum number of child nodes 186 */ 187 public int getChildrenMax() { 188 return Integer.parseInt(getFieldValue(ConfigureNodeFields.children_max)); 189 } 190 191 /** 192 * Set the maximum number of child nodes that can be associated with a collection node. 193 * 194 * @param max The maximum number of child nodes. 195 */ 196 public void setChildrenMax(int max) { 197 addField(ConfigureNodeFields.children_max, FormField.Type.text_single); 198 setAnswer(ConfigureNodeFields.children_max.getFieldName(), max); 199 } 200 201 /** 202 * Gets the collection node which the node is affiliated with. 203 * 204 * @return The collection node id 205 */ 206 public String getCollection() { 207 return getFieldValue(ConfigureNodeFields.collection); 208 } 209 210 /** 211 * Sets the collection node which the node is affiliated with. 212 * 213 * @param collection The node id of the collection node 214 */ 215 public void setCollection(String collection) { 216 addField(ConfigureNodeFields.collection, FormField.Type.text_single); 217 setAnswer(ConfigureNodeFields.collection.getFieldName(), collection); 218 } 219 220 /** 221 * Gets the URL of an XSL transformation which can be applied to the payload 222 * format in order to generate a valid Data Forms result that the client could 223 * display using a generic Data Forms rendering engine. 224 * 225 * @return The URL of an XSL transformation 226 */ 227 public String getDataformXSLT() { 228 return getFieldValue(ConfigureNodeFields.dataform_xslt); 229 } 230 231 /** 232 * Sets the URL of an XSL transformation which can be applied to the payload 233 * format in order to generate a valid Data Forms result that the client could 234 * display using a generic Data Forms rendering engine. 235 * 236 * @param url The URL of an XSL transformation 237 */ 238 public void setDataformXSLT(String url) { 239 addField(ConfigureNodeFields.dataform_xslt, FormField.Type.text_single); 240 setAnswer(ConfigureNodeFields.dataform_xslt.getFieldName(), url); 241 } 242 243 /** 244 * Does the node deliver payloads with event notifications. 245 * 246 * @return true if it does, false otherwise 247 */ 248 public boolean isDeliverPayloads() { 249 return parseBoolean(getFieldValue(ConfigureNodeFields.deliver_payloads)); 250 } 251 252 /** 253 * Sets whether the node will deliver payloads with event notifications. 254 * 255 * @param deliver true if the payload will be delivered, false otherwise 256 */ 257 public void setDeliverPayloads(boolean deliver) { 258 addField(ConfigureNodeFields.deliver_payloads, FormField.Type.bool); 259 setAnswer(ConfigureNodeFields.deliver_payloads.getFieldName(), deliver); 260 } 261 262 /** 263 * Determines who should get replies to items. 264 * 265 * @return Who should get the reply 266 */ 267 public ItemReply getItemReply() { 268 String value = getFieldValue(ConfigureNodeFields.itemreply); 269 270 if (value == null) 271 return null; 272 else 273 return ItemReply.valueOf(value); 274 } 275 276 /** 277 * Sets who should get the replies to items. 278 * 279 * @param reply Defines who should get the reply 280 */ 281 public void setItemReply(ItemReply reply) { 282 addField(ConfigureNodeFields.itemreply, FormField.Type.list_single); 283 setAnswer(ConfigureNodeFields.itemreply.getFieldName(), getListSingle(reply.toString())); 284 } 285 286 /** 287 * Gets the maximum number of items to persisted to this node if {@link #isPersistItems()} is 288 * true. 289 * 290 * @return The maximum number of items to persist 291 */ 292 public int getMaxItems() { 293 return Integer.parseInt(getFieldValue(ConfigureNodeFields.max_items)); 294 } 295 296 /** 297 * Set the maximum number of items to persisted to this node if {@link #isPersistItems()} is 298 * true. 299 * 300 * @param max The maximum number of items to persist 301 */ 302 public void setMaxItems(int max) { 303 addField(ConfigureNodeFields.max_items, FormField.Type.text_single); 304 setAnswer(ConfigureNodeFields.max_items.getFieldName(), max); 305 } 306 307 /** 308 * Gets the maximum payload size in bytes. 309 * 310 * @return The maximum payload size 311 */ 312 public int getMaxPayloadSize() { 313 return Integer.parseInt(getFieldValue(ConfigureNodeFields.max_payload_size)); 314 } 315 316 /** 317 * Sets the maximum payload size in bytes. 318 * 319 * @param max The maximum payload size 320 */ 321 public void setMaxPayloadSize(int max) { 322 addField(ConfigureNodeFields.max_payload_size, FormField.Type.text_single); 323 setAnswer(ConfigureNodeFields.max_payload_size.getFieldName(), max); 324 } 325 326 /** 327 * Gets the node type. 328 * 329 * @return The node type 330 */ 331 public NodeType getNodeType() { 332 String value = getFieldValue(ConfigureNodeFields.node_type); 333 334 if (value == null) 335 return null; 336 else 337 return NodeType.valueOf(value); 338 } 339 340 /** 341 * Sets the node type. 342 * 343 * @param type The node type 344 */ 345 public void setNodeType(NodeType type) { 346 addField(ConfigureNodeFields.node_type, FormField.Type.list_single); 347 setAnswer(ConfigureNodeFields.node_type.getFieldName(), getListSingle(type.toString())); 348 } 349 350 /** 351 * Determines if subscribers should be notified when the configuration changes. 352 * 353 * @return true if they should be notified, false otherwise 354 */ 355 public boolean isNotifyConfig() { 356 return parseBoolean(getFieldValue(ConfigureNodeFields.notify_config)); 357 } 358 359 /** 360 * Sets whether subscribers should be notified when the configuration changes. 361 * 362 * @param notify true if subscribers should be notified, false otherwise 363 */ 364 public void setNotifyConfig(boolean notify) { 365 addField(ConfigureNodeFields.notify_config, FormField.Type.bool); 366 setAnswer(ConfigureNodeFields.notify_config.getFieldName(), notify); 367 } 368 369 /** 370 * Determines whether subscribers should be notified when the node is deleted. 371 * 372 * @return true if subscribers should be notified, false otherwise 373 */ 374 public boolean isNotifyDelete() { 375 return parseBoolean(getFieldValue(ConfigureNodeFields.notify_delete)); 376 } 377 378 /** 379 * Sets whether subscribers should be notified when the node is deleted. 380 * 381 * @param notify true if subscribers should be notified, false otherwise 382 */ 383 public void setNotifyDelete(boolean notify) { 384 addField(ConfigureNodeFields.notify_delete, FormField.Type.bool); 385 setAnswer(ConfigureNodeFields.notify_delete.getFieldName(), notify); 386 } 387 388 /** 389 * Determines whether subscribers should be notified when items are deleted 390 * from the node. 391 * 392 * @return true if subscribers should be notified, false otherwise 393 */ 394 public boolean isNotifyRetract() { 395 return parseBoolean(getFieldValue(ConfigureNodeFields.notify_retract)); 396 } 397 398 /** 399 * Sets whether subscribers should be notified when items are deleted 400 * from the node. 401 * 402 * @param notify true if subscribers should be notified, false otherwise 403 */ 404 public void setNotifyRetract(boolean notify) { 405 addField(ConfigureNodeFields.notify_retract, FormField.Type.bool); 406 setAnswer(ConfigureNodeFields.notify_retract.getFieldName(), notify); 407 } 408 409 /** 410 * Determines the type of notifications which are sent. 411 * 412 * @return NotificationType for the node configuration 413 * @since 4.3 414 */ 415 public NotificationType getNotificationType() { 416 String value = getFieldValue(ConfigureNodeFields.notification_type); 417 if (value == null) 418 return null; 419 return NotificationType.valueOf(value); 420 } 421 422 /** 423 * Sets the NotificationType for the node. 424 * 425 * @param notificationType The enum representing the possible options 426 * @since 4.3 427 */ 428 public void setNotificationType(NotificationType notificationType) { 429 addField(ConfigureNodeFields.notification_type, FormField.Type.list_single); 430 setAnswer(ConfigureNodeFields.notification_type.getFieldName(), getListSingle(notificationType.toString())); 431 } 432 433 /** 434 * Determines whether items should be persisted in the node. 435 * 436 * @return true if items are persisted 437 */ 438 public boolean isPersistItems() { 439 return parseBoolean(getFieldValue(ConfigureNodeFields.persist_items)); 440 } 441 442 /** 443 * Sets whether items should be persisted in the node. 444 * 445 * @param persist true if items should be persisted, false otherwise 446 */ 447 public void setPersistentItems(boolean persist) { 448 addField(ConfigureNodeFields.persist_items, FormField.Type.bool); 449 setAnswer(ConfigureNodeFields.persist_items.getFieldName(), persist); 450 } 451 452 /** 453 * Determines whether to deliver notifications to available users only. 454 * 455 * @return true if users must be available 456 */ 457 public boolean isPresenceBasedDelivery() { 458 return parseBoolean(getFieldValue(ConfigureNodeFields.presence_based_delivery)); 459 } 460 461 /** 462 * Sets whether to deliver notifications to available users only. 463 * 464 * @param presenceBased true if user must be available, false otherwise 465 */ 466 public void setPresenceBasedDelivery(boolean presenceBased) { 467 addField(ConfigureNodeFields.presence_based_delivery, FormField.Type.bool); 468 setAnswer(ConfigureNodeFields.presence_based_delivery.getFieldName(), presenceBased); 469 } 470 471 /** 472 * Gets the publishing model for the node, which determines who may publish to it. 473 * 474 * @return The publishing model 475 */ 476 public PublishModel getPublishModel() { 477 String value = getFieldValue(ConfigureNodeFields.publish_model); 478 479 if (value == null) 480 return null; 481 else 482 return PublishModel.valueOf(value); 483 } 484 485 /** 486 * Sets the publishing model for the node, which determines who may publish to it. 487 * 488 * @param publish The enum representing the possible options for the publishing model 489 */ 490 public void setPublishModel(PublishModel publish) { 491 addField(ConfigureNodeFields.publish_model, FormField.Type.list_single); 492 setAnswer(ConfigureNodeFields.publish_model.getFieldName(), getListSingle(publish.toString())); 493 } 494 495 /** 496 * List of the multi user chat rooms that are specified as reply rooms. 497 * 498 * @return The reply room JID's 499 */ 500 public List<String> getReplyRoom() { 501 return getFieldValues(ConfigureNodeFields.replyroom); 502 } 503 504 /** 505 * Sets the multi user chat rooms that are specified as reply rooms. 506 * 507 * @param replyRooms The multi user chat room to use as reply rooms 508 */ 509 public void setReplyRoom(List<String> replyRooms) { 510 addField(ConfigureNodeFields.replyroom, FormField.Type.list_multi); 511 setAnswer(ConfigureNodeFields.replyroom.getFieldName(), replyRooms); 512 } 513 514 /** 515 * Gets the specific JID's for reply to. 516 * 517 * @return The JID's 518 */ 519 public List<String> getReplyTo() { 520 return getFieldValues(ConfigureNodeFields.replyto); 521 } 522 523 /** 524 * Sets the specific JID's for reply to. 525 * 526 * @param replyTos The JID's to reply to 527 */ 528 public void setReplyTo(List<String> replyTos) { 529 addField(ConfigureNodeFields.replyto, FormField.Type.list_multi); 530 setAnswer(ConfigureNodeFields.replyto.getFieldName(), replyTos); 531 } 532 533 /** 534 * Gets the roster groups that are allowed to subscribe and retrieve items. 535 * 536 * @return The roster groups 537 */ 538 public List<String> getRosterGroupsAllowed() { 539 return getFieldValues(ConfigureNodeFields.roster_groups_allowed); 540 } 541 542 /** 543 * Sets the roster groups that are allowed to subscribe and retrieve items. 544 * 545 * @param groups The roster groups 546 */ 547 public void setRosterGroupsAllowed(List<String> groups) { 548 addField(ConfigureNodeFields.roster_groups_allowed, FormField.Type.list_multi); 549 setAnswer(ConfigureNodeFields.roster_groups_allowed.getFieldName(), groups); 550 } 551 552 /** 553 * Determines if subscriptions are allowed. 554 * 555 * @return true if subscriptions are allowed, false otherwise 556 * @deprecated use {@link #isSubscribe()} instead 557 */ 558 @Deprecated 559 public boolean isSubscibe() { 560 return isSubscribe(); 561 } 562 563 /** 564 * Determines if subscriptions are allowed. 565 * 566 * @return true if subscriptions are allowed, false otherwise 567 */ 568 public boolean isSubscribe() { 569 return parseBoolean(getFieldValue(ConfigureNodeFields.subscribe)); 570 } 571 572 /** 573 * Sets whether subscriptions are allowed. 574 * 575 * @param subscribe true if they are, false otherwise 576 */ 577 public void setSubscribe(boolean subscribe) { 578 addField(ConfigureNodeFields.subscribe, FormField.Type.bool); 579 setAnswer(ConfigureNodeFields.subscribe.getFieldName(), subscribe); 580 } 581 582 /** 583 * Gets the human readable node title. 584 * 585 * @return The node title 586 */ 587 @Override 588 public String getTitle() { 589 return getFieldValue(ConfigureNodeFields.title); 590 } 591 592 /** 593 * Sets a human readable title for the node. 594 * 595 * @param title The node title 596 */ 597 @Override 598 public void setTitle(String title) { 599 addField(ConfigureNodeFields.title, FormField.Type.text_single); 600 setAnswer(ConfigureNodeFields.title.getFieldName(), title); 601 } 602 603 /** 604 * The type of node data, usually specified by the namespace of the payload (if any). 605 * 606 * @return The type of node data 607 */ 608 public String getDataType() { 609 return getFieldValue(ConfigureNodeFields.type); 610 } 611 612 /** 613 * Sets the type of node data, usually specified by the namespace of the payload (if any). 614 * 615 * @param type The type of node data 616 */ 617 public void setDataType(String type) { 618 addField(ConfigureNodeFields.type, FormField.Type.text_single); 619 setAnswer(ConfigureNodeFields.type.getFieldName(), type); 620 } 621 622 @Override 623 public String toString() { 624 StringBuilder result = new StringBuilder(getClass().getName() + " Content ["); 625 626 for (FormField formField : getFields()) { 627 result.append('('); 628 result.append(formField.getVariable()); 629 result.append(':'); 630 631 StringBuilder valuesBuilder = new StringBuilder(); 632 633 for (CharSequence value : formField.getValues()) { 634 if (valuesBuilder.length() > 0) 635 result.append(','); 636 valuesBuilder.append(value); 637 } 638 639 if (valuesBuilder.length() == 0) 640 valuesBuilder.append("NOT SET"); 641 result.append(valuesBuilder); 642 result.append(')'); 643 } 644 result.append(']'); 645 return result.toString(); 646 } 647 648 private static boolean parseBoolean(String fieldValue) { 649 return ("1".equals(fieldValue) || "true".equals(fieldValue)); 650 } 651 652 private String getFieldValue(ConfigureNodeFields field) { 653 FormField formField = getField(field.getFieldName()); 654 655 return formField.getFirstValue(); 656 } 657 658 private List<String> getFieldValues(ConfigureNodeFields field) { 659 FormField formField = getField(field.getFieldName()); 660 661 return formField.getValuesAsString(); 662 } 663 664 private void addField(ConfigureNodeFields nodeField, FormField.Type type) { 665 String fieldName = nodeField.getFieldName(); 666 667 if (getField(fieldName) == null) { 668 FormField field = new FormField(fieldName); 669 field.setType(type); 670 addField(field); 671 } 672 } 673 674 private static List<String> getListSingle(String value) { 675 List<String> list = new ArrayList<>(1); 676 list.add(value); 677 return list; 678 } 679 680}