001/* 002 * The contents of this file are subject to the terms of the Common Development and 003 * Distribution License (the License). You may not use this file except in compliance with the 004 * License. 005 * 006 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the 007 * specific language governing permission and limitations under the License. 008 * 009 * When distributing Covered Software, include this CDDL Header Notice in each file and include 010 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL 011 * Header, with the fields enclosed by brackets [] replaced by your own identifying 012 * information: "Portions Copyright [year] [name of copyright owner]". 013 * 014 * Copyright 2012-2015 ForgeRock AS. 015 */ 016 017package org.forgerock.json.resource; 018 019import static org.forgerock.util.Utils.*; 020 021import java.util.ArrayList; 022import java.util.Collections; 023import java.util.HashMap; 024import java.util.LinkedHashMap; 025import java.util.LinkedList; 026import java.util.List; 027import java.util.Map; 028 029import org.forgerock.http.routing.Version; 030import org.forgerock.json.JsonException; 031import org.forgerock.json.JsonPointer; 032import org.forgerock.json.JsonValue; 033import org.forgerock.util.i18n.PreferredLocales; 034 035/** 036 * A utility class containing various factory methods for creating and 037 * manipulating requests. 038 */ 039public final class Requests { 040 private static abstract class AbstractRequestImpl<T extends Request> implements Request { 041 private final List<JsonPointer> fields = new LinkedList<>(); 042 private ResourcePath resourcePath; 043 private final Map<String, String> parameters = new LinkedHashMap<>(2); 044 private Version resourceVersion; 045 private PreferredLocales preferredLocales; 046 047 protected AbstractRequestImpl() { 048 // Default constructor. 049 } 050 051 protected AbstractRequestImpl(final Request request) { 052 this.resourcePath = request.getResourcePathObject(); 053 this.fields.addAll(request.getFields()); 054 this.parameters.putAll(request.getAdditionalParameters()); 055 this.resourceVersion = request.getResourceVersion(); 056 this.preferredLocales = request.getPreferredLocales(); 057 } 058 059 @Override 060 public final T addField(final JsonPointer... fields) { 061 for (final JsonPointer field : fields) { 062 this.fields.add(notNull(field)); 063 } 064 return getThis(); 065 } 066 067 @Override 068 public final T addField(final String... fields) { 069 try { 070 for (final String field : fields) { 071 this.fields.add(new JsonPointer(field)); 072 } 073 } catch (final JsonException e) { 074 throw new IllegalArgumentException(e.getMessage()); 075 } 076 return getThis(); 077 } 078 079 @Override 080 public final List<JsonPointer> getFields() { 081 return fields; 082 } 083 084 @Override 085 public final String getResourcePath() { 086 return resourcePath.toString(); 087 } 088 089 @Override 090 public final ResourcePath getResourcePathObject() { 091 return resourcePath; 092 } 093 094 @Override 095 public Map<String, String> getAdditionalParameters() { 096 return parameters; 097 } 098 099 @Override 100 public String getAdditionalParameter(final String name) { 101 return parameters.get(name); 102 } 103 104 @Override 105 public Version getResourceVersion() { 106 return resourceVersion; 107 } 108 109 @Override 110 public final T setResourcePath(final String path) { 111 resourcePath = ResourcePath.valueOf(path); 112 return getThis(); 113 } 114 115 @Override 116 public final T setResourcePath(final ResourcePath path) { 117 resourcePath = notNull(path); 118 return getThis(); 119 } 120 121 @Override 122 public T setAdditionalParameter(final String name, final String value) throws BadRequestException { 123 if (isReservedParameter(name)) { 124 throw new BadRequestException("Unrecognized request parameter '" + name + "'"); 125 } 126 parameters.put(notNull(name), value); 127 return getThis(); 128 } 129 130 @Override 131 public T setResourceVersion(Version resourceVersion) { 132 this.resourceVersion = resourceVersion; 133 return getThis(); 134 } 135 136 boolean isReservedParameter(String name) { 137 return name.startsWith("_"); 138 } 139 140 protected abstract T getThis(); 141 142 @Override 143 public JsonValue toJsonValue() { 144 return new JsonValue(new HashMap<>()) 145 .put("method", getRequestType().name().toLowerCase()) 146 .put(FIELD_RESOURCE_PATH, getResourcePath()) 147 .put(FIELD_FIELDS, getFields()); 148 } 149 150 @Override 151 public String toString() { 152 return toJsonValue().toString(); 153 } 154 155 @Override 156 public PreferredLocales getPreferredLocales() { 157 return preferredLocales; 158 } 159 160 @Override 161 public T setPreferredLocales(PreferredLocales preferredLocales) { 162 this.preferredLocales = preferredLocales; 163 return getThis(); 164 } 165 } 166 167 private static final class ActionRequestImpl extends AbstractRequestImpl<ActionRequest> 168 implements ActionRequest { 169 private String actionId; 170 private JsonValue content; 171 172 private ActionRequestImpl() { 173 // Default constructor. 174 content = new JsonValue(null); 175 } 176 177 private ActionRequestImpl(final ActionRequest request) { 178 super(request); 179 this.actionId = request.getAction(); 180 this.content = copyJsonValue(request.getContent()); 181 } 182 183 @Override 184 public <R, P> R accept(final RequestVisitor<R, P> v, final P p) { 185 return v.visitActionRequest(p, this); 186 } 187 188 @Override 189 public String getAction() { 190 return actionId; 191 } 192 193 @Override 194 public <T extends Enum<T>> T getActionAsEnum(final Class<T> type) { 195 return asEnum(getAction(), type); 196 } 197 198 @Override 199 public JsonValue getContent() { 200 return content; 201 } 202 203 @Override 204 public ActionRequest setAction(final String id) { 205 this.actionId = notNull(id); 206 return this; 207 } 208 209 @Override 210 public ActionRequest setContent(final JsonValue content) { 211 this.content = content != null ? content : new JsonValue(null); 212 return this; 213 } 214 215 @Override 216 protected ActionRequest getThis() { 217 return this; 218 } 219 220 @Override 221 public RequestType getRequestType() { 222 return RequestType.ACTION; 223 } 224 225 @Override 226 public JsonValue toJsonValue() { 227 return super.toJsonValue() 228 .put(FIELD_ACTION, String.valueOf(getAction())) 229 .put(FIELD_CONTENT, getContent().getObject()) 230 .put(FIELD_ADDITIONAL_PARAMETERS, getAdditionalParameters()); 231 } 232 233 @Override 234 boolean isReservedParameter(String name) { 235 // no reserved parameters for ActionRequests in order to support current patch-by-query usage *except* 236 // mimeType which only applies to true read requests. 237 return name.equals("_mimeType"); 238 } 239 } 240 241 private static final class CreateRequestImpl extends AbstractRequestImpl<CreateRequest> 242 implements CreateRequest { 243 private JsonValue content; 244 private String newResourceId; 245 246 private CreateRequestImpl() { 247 // Default constructor. 248 } 249 250 private CreateRequestImpl(final CreateRequest request) { 251 super(request); 252 this.content = copyJsonValue(request.getContent()); 253 this.newResourceId = request.getNewResourceId(); 254 } 255 256 @Override 257 public <R, P> R accept(final RequestVisitor<R, P> v, final P p) { 258 return v.visitCreateRequest(p, this); 259 } 260 261 @Override 262 public JsonValue getContent() { 263 return content; 264 } 265 266 @Override 267 public String getNewResourceId() { 268 return newResourceId; 269 } 270 271 @Override 272 public CreateRequest setContent(final JsonValue content) { 273 this.content = notNull(content); 274 return this; 275 } 276 277 @Override 278 public CreateRequest setNewResourceId(final String id) { 279 this.newResourceId = id; 280 return this; 281 } 282 283 @Override 284 protected CreateRequest getThis() { 285 return this; 286 } 287 288 @Override 289 public RequestType getRequestType() { 290 return RequestType.CREATE; 291 } 292 293 @Override 294 public JsonValue toJsonValue() { 295 return super.toJsonValue() 296 .put(FIELD_NEW_RESOURCE_ID, getNewResourceId()) 297 .put(FIELD_CONTENT, getContent().getObject()); 298 } 299 300 } 301 302 private static final class DeleteRequestImpl extends AbstractRequestImpl<DeleteRequest> 303 implements DeleteRequest { 304 private String version; 305 306 private DeleteRequestImpl() { 307 // Default constructor. 308 } 309 310 private DeleteRequestImpl(final DeleteRequest request) { 311 super(request); 312 this.version = request.getRevision(); 313 } 314 315 @Override 316 public <R, P> R accept(final RequestVisitor<R, P> v, final P p) { 317 return v.visitDeleteRequest(p, this); 318 } 319 320 @Override 321 public String getRevision() { 322 return version; 323 } 324 325 @Override 326 public DeleteRequest setRevision(final String version) { 327 this.version = version; 328 return this; 329 } 330 331 @Override 332 protected DeleteRequest getThis() { 333 return this; 334 } 335 336 @Override 337 public RequestType getRequestType() { 338 return RequestType.DELETE; 339 } 340 341 @Override 342 public JsonValue toJsonValue() { 343 return super.toJsonValue() 344 .put(FIELD_REVISION, String.valueOf(getRevision())); 345 } 346 347 } 348 349 private static final class PatchRequestImpl extends AbstractRequestImpl<PatchRequest> implements 350 PatchRequest { 351 private List<PatchOperation> operations; 352 private String version; 353 354 private PatchRequestImpl() { 355 operations = new LinkedList<>(); 356 } 357 358 private PatchRequestImpl(final PatchRequest request) { 359 super(request); 360 this.operations = new LinkedList<>(request.getPatchOperations()); 361 this.version = request.getRevision(); 362 } 363 364 @Override 365 public <R, P> R accept(final RequestVisitor<R, P> v, final P p) { 366 return v.visitPatchRequest(p, this); 367 } 368 369 @Override 370 public String getRevision() { 371 return version; 372 } 373 374 @Override 375 public PatchRequest addPatchOperation(PatchOperation... operations) { 376 Collections.addAll(this.operations, operations); 377 return this; 378 } 379 380 @Override 381 public List<PatchOperation> getPatchOperations() { 382 return operations; 383 } 384 385 @Override 386 public PatchRequest addPatchOperation(String operation, String field, JsonValue value) { 387 operations.add(PatchOperation.operation(operation, field, value)); 388 return this; 389 } 390 391 @Override 392 public PatchRequest setRevision(final String version) { 393 this.version = version; 394 return this; 395 } 396 397 @Override 398 protected PatchRequest getThis() { 399 return this; 400 } 401 402 @Override 403 public RequestType getRequestType() { 404 return RequestType.PATCH; 405 } 406 407 @Override 408 public JsonValue toJsonValue() { 409 final List<Object> operations = new ArrayList<>(); 410 for (PatchOperation operation : getPatchOperations()) { 411 operations.add(operation.toJsonValue().getObject()); 412 } 413 return super.toJsonValue() 414 .put(FIELD_REVISION, String.valueOf(getRevision())) 415 .put(FIELD_PATCH_OPERATIONS, operations); 416 } 417 } 418 419 private static final class QueryRequestImpl extends AbstractRequestImpl<QueryRequest> implements 420 QueryRequest { 421 private org.forgerock.util.query.QueryFilter<JsonPointer> filter; 422 private final List<SortKey> keys = new LinkedList<>(); 423 private String pagedResultsCookie; 424 private CountPolicy totalPagedResultsPolicy = CountPolicy.NONE; 425 private int pagedResultsOffset = 0; 426 private int pageSize = 0; 427 private String queryId; 428 private String queryExpression; 429 430 private QueryRequestImpl() { 431 // Default constructor. 432 } 433 434 private QueryRequestImpl(final QueryRequest request) { 435 super(request); 436 this.filter = request.getQueryFilter(); 437 this.queryId = request.getQueryId(); 438 this.queryExpression = request.getQueryExpression(); 439 this.keys.addAll(request.getSortKeys()); 440 this.pageSize = request.getPageSize(); 441 this.pagedResultsCookie = request.getPagedResultsCookie(); 442 this.pagedResultsOffset = request.getPagedResultsOffset(); 443 this.totalPagedResultsPolicy = request.getTotalPagedResultsPolicy(); 444 } 445 446 @Override 447 public <R, P> R accept(final RequestVisitor<R, P> v, final P p) { 448 return v.visitQueryRequest(p, this); 449 } 450 451 @Override 452 public QueryRequest addSortKey(final SortKey... keys) { 453 for (final SortKey key : keys) { 454 this.keys.add(notNull(key)); 455 } 456 return this; 457 } 458 459 @Override 460 public final QueryRequest addSortKey(final String... keys) { 461 for (final String key : keys) { 462 this.keys.add(SortKey.valueOf(key)); 463 } 464 return this; 465 } 466 467 @Override 468 public String getPagedResultsCookie() { 469 return pagedResultsCookie; 470 } 471 472 @Override 473 public CountPolicy getTotalPagedResultsPolicy() { 474 return totalPagedResultsPolicy; 475 } 476 477 @Override 478 public int getPagedResultsOffset() { 479 return pagedResultsOffset; 480 } 481 482 @Override 483 public int getPageSize() { 484 return pageSize; 485 } 486 487 @Override 488 public org.forgerock.util.query.QueryFilter<JsonPointer> getQueryFilter() { 489 return filter; 490 } 491 492 @Override 493 public String getQueryId() { 494 return queryId; 495 } 496 497 @Override 498 public String getQueryExpression() { 499 return queryExpression; 500 } 501 502 @Override 503 public List<SortKey> getSortKeys() { 504 return keys; 505 } 506 507 @Override 508 public QueryRequest setPagedResultsCookie(final String cookie) { 509 this.pagedResultsCookie = cookie; 510 return this; 511 } 512 513 @Override 514 public QueryRequest setTotalPagedResultsPolicy(final CountPolicy totalPagedResultsPolicy) { 515 this.totalPagedResultsPolicy = notNull(totalPagedResultsPolicy); 516 return this; 517 } 518 519 @Override 520 public QueryRequest setPagedResultsOffset(int offset) { 521 this.pagedResultsOffset = offset; 522 return this; 523 } 524 525 @Override 526 public QueryRequest setPageSize(final int size) { 527 this.pageSize = size; 528 return this; 529 } 530 531 @Override 532 public QueryRequest setQueryExpression(final String expression) { 533 this.queryExpression = expression; 534 return this; 535 } 536 537 @Override 538 public QueryRequest setQueryFilter(final org.forgerock.util.query.QueryFilter<JsonPointer> filter) { 539 this.filter = filter; 540 return this; 541 } 542 543 @Override 544 public QueryRequest setQueryId(final String id) { 545 this.queryId = id; 546 return this; 547 } 548 549 @Override 550 protected QueryRequest getThis() { 551 return this; 552 } 553 554 @Override 555 public RequestType getRequestType() { 556 return RequestType.QUERY; 557 } 558 559 @Override 560 public JsonValue toJsonValue() { 561 final List<String> sortKeys = new ArrayList<>(); 562 for (SortKey key : getSortKeys()) { 563 sortKeys.add(String.valueOf(key)); 564 } 565 return super.toJsonValue() 566 .put(FIELD_QUERY_ID, String.valueOf(getQueryId())) 567 .put(FIELD_QUERY_EXPRESSION, String.valueOf(getQueryExpression())) 568 .put(FIELD_QUERY_FILTER, String.valueOf(getQueryFilter())) 569 .put(FIELD_SORT_KEYS, sortKeys) 570 .put(FIELD_PAGE_SIZE, String.valueOf(getPageSize())) 571 .put(FIELD_PAGED_RESULTS_OFFSET, String.valueOf(getPagedResultsOffset())) 572 .put(FIELD_PAGED_RESULTS_COOKIE, String.valueOf(getPagedResultsCookie())) 573 .put(FIELD_TOTAL_PAGED_RESULTS_POLICY, String.valueOf(getTotalPagedResultsPolicy())) 574 .put(FIELD_ADDITIONAL_PARAMETERS, getAdditionalParameters()); 575 } 576 } 577 578 private static final class ReadRequestImpl extends AbstractRequestImpl<ReadRequest> implements 579 ReadRequest { 580 581 private ReadRequestImpl() { 582 // Default constructor. 583 } 584 585 private ReadRequestImpl(final ReadRequest request) { 586 super(request); 587 } 588 589 @Override 590 public <R, P> R accept(final RequestVisitor<R, P> v, final P p) { 591 return v.visitReadRequest(p, this); 592 } 593 594 @Override 595 protected ReadRequest getThis() { 596 return this; 597 } 598 599 @Override 600 public RequestType getRequestType() { 601 return RequestType.READ; 602 } 603 } 604 605 private static final class UpdateRequestImpl extends AbstractRequestImpl<UpdateRequest> 606 implements UpdateRequest { 607 private JsonValue content; 608 private String version; 609 610 private UpdateRequestImpl() { 611 // Default constructor. 612 } 613 614 private UpdateRequestImpl(final UpdateRequest request) { 615 super(request); 616 this.version = request.getRevision(); 617 this.content = copyJsonValue(request.getContent()); 618 } 619 620 @Override 621 public <R, P> R accept(final RequestVisitor<R, P> v, final P p) { 622 return v.visitUpdateRequest(p, this); 623 } 624 625 @Override 626 public JsonValue getContent() { 627 return content; 628 } 629 630 @Override 631 public String getRevision() { 632 return version; 633 } 634 635 @Override 636 public UpdateRequest setContent(final JsonValue content) { 637 this.content = notNull(content); 638 return this; 639 } 640 641 @Override 642 public UpdateRequest setRevision(final String version) { 643 this.version = version; 644 return this; 645 } 646 647 @Override 648 protected UpdateRequest getThis() { 649 return this; 650 } 651 652 @Override 653 public RequestType getRequestType() { 654 return RequestType.UPDATE; 655 } 656 657 @Override 658 public JsonValue toJsonValue() { 659 return super.toJsonValue() 660 .put(FIELD_REVISION, String.valueOf(getRevision())) 661 .put(FIELD_CONTENT, getContent().getObject()); 662 } 663 } 664 665 /** 666 * Returns a copy of the provided action request. 667 * 668 * @param request 669 * The action request to be copied. 670 * @return The action request copy. 671 */ 672 public static ActionRequest copyOfActionRequest(final ActionRequest request) { 673 return new ActionRequestImpl(request); 674 } 675 676 /** 677 * Returns a copy of the provided create request. 678 * 679 * @param request 680 * The create request to be copied. 681 * @return The create request copy. 682 */ 683 public static CreateRequest copyOfCreateRequest(final CreateRequest request) { 684 return new CreateRequestImpl(request); 685 } 686 687 /** 688 * Returns a copy of the provided delete request. 689 * 690 * @param request 691 * The delete request to be copied. 692 * @return The delete request copy. 693 */ 694 public static DeleteRequest copyOfDeleteRequest(final DeleteRequest request) { 695 return new DeleteRequestImpl(request); 696 } 697 698 /** 699 * Returns a copy of the provided patch request. 700 * 701 * @param request 702 * The patch request to be copied. 703 * @return The patch request copy. 704 */ 705 public static PatchRequest copyOfPatchRequest(final PatchRequest request) { 706 return new PatchRequestImpl(request); 707 } 708 709 /** 710 * Returns a copy of the provided query request. 711 * 712 * @param request 713 * The query request to be copied. 714 * @return The query request copy. 715 */ 716 public static QueryRequest copyOfQueryRequest(final QueryRequest request) { 717 return new QueryRequestImpl(request); 718 } 719 720 /** 721 * Returns a copy of the provided read request. 722 * 723 * @param request 724 * The read request to be copied. 725 * @return The read request copy. 726 */ 727 public static ReadRequest copyOfReadRequest(final ReadRequest request) { 728 return new ReadRequestImpl(request); 729 } 730 731 /** 732 * Returns a copy of the provided update request. 733 * 734 * @param request 735 * The update request to be copied. 736 * @return The update request copy. 737 */ 738 public static UpdateRequest copyOfUpdateRequest(final UpdateRequest request) { 739 return new UpdateRequestImpl(request); 740 } 741 742 /** 743 * Returns a new action request with the provided resource path and action 744 * ID. Invoking this method as follows: 745 * 746 * <pre> 747 * newActionRequest("users/1", actionId); 748 * </pre> 749 * 750 * Is equivalent to: 751 * 752 * <pre> 753 * newActionRequest("users", "1", actionId); 754 * </pre> 755 * 756 * Except that the resource ID is already URL encoded in the first form. 757 * 758 * @param resourcePath 759 * The URL-encoded resource path. 760 * @param actionId 761 * The action ID. 762 * @return The new action request. 763 */ 764 public static ActionRequest newActionRequest(final String resourcePath, final String actionId) { 765 return new ActionRequestImpl().setResourcePath(resourcePath).setAction(actionId); 766 } 767 768 /** 769 * Returns a new action request with the provided resource path and action 770 * ID. 771 * 772 * @param resourcePath 773 * The parsed resource path. 774 * @param actionId 775 * The action ID. 776 * @return The new action request. 777 */ 778 public static ActionRequest newActionRequest(final ResourcePath resourcePath, 779 final String actionId) { 780 return new ActionRequestImpl().setResourcePath(resourcePath).setAction(actionId); 781 } 782 783 /** 784 * Returns a new action request with the provided resource container path, 785 * resource ID, and action ID. Invoking this method as follows: 786 * 787 * <pre> 788 * newActionRequest("users", "1", "someAction"); 789 * </pre> 790 * 791 * Is equivalent to: 792 * 793 * <pre> 794 * newActionRequest("users/1", "someAction"); 795 * </pre> 796 * 797 * Except that the resource ID is already URL encoded in the second form. 798 * 799 * @param resourceContainer 800 * The URL-encoded path of the resource container. 801 * @param resourceId 802 * The URL decoded ID of the resource. 803 * @param actionId 804 * The action ID. 805 * @return The new action request. 806 */ 807 public static ActionRequest newActionRequest(final String resourceContainer, 808 final String resourceId, final String actionId) { 809 return newActionRequest(ResourcePath.valueOf(resourceContainer), resourceId, actionId); 810 } 811 812 /** 813 * Returns a new action request with the provided resource container path, 814 * resource ID, and action ID. 815 * 816 * @param resourceContainer 817 * The parsed path of the resource container. 818 * @param resourceId 819 * The URL decoded ID of the resource. 820 * @param actionId 821 * The action ID. 822 * @return The new action request. 823 */ 824 public static ActionRequest newActionRequest(final ResourcePath resourceContainer, 825 final String resourceId, final String actionId) { 826 return newActionRequest(resourceContainer.child(resourceId), actionId); 827 } 828 829 /** 830 * Returns a new create request with the provided resource path, and JSON 831 * content. The create request will have a {@code null} new resource ID, 832 * indicating that the server will be responsible for generating the ID of 833 * the new resource. Invoking this method as follows: 834 * 835 * <pre> 836 * newCreateRequest("users/1", content); 837 * </pre> 838 * 839 * Is equivalent to: 840 * 841 * <pre> 842 * newCreateRequest("users", "1", content); 843 * </pre> 844 * 845 * Except that the resource ID is already URL encoded in the first form. 846 * 847 * @param resourceContainer 848 * The URL-encoded path of the resource container beneath which the new 849 * resource should be created. 850 * @param content 851 * The JSON content. 852 * @return The new create request. 853 */ 854 public static CreateRequest newCreateRequest(final String resourceContainer, 855 final JsonValue content) { 856 return new CreateRequestImpl().setResourcePath(resourceContainer).setContent(content); 857 } 858 859 /** 860 * Returns a new create request with the provided resource path, and JSON 861 * content. The create request will have a {@code null} new resource ID, 862 * indicating that the server will be responsible for generating the ID of 863 * the new resource. 864 * 865 * @param resourceContainer 866 * The parsed path of the resource container beneath which the 867 * new resource should be created. 868 * @param content 869 * The JSON content. 870 * @return The new create request. 871 */ 872 public static CreateRequest newCreateRequest(final ResourcePath resourceContainer, 873 final JsonValue content) { 874 return new CreateRequestImpl().setResourcePath(resourceContainer).setContent(content); 875 } 876 877 /** 878 * Returns a new create request with the provided resource path, new 879 * resource ID, and JSON content. Invoking this method as follows: 880 * 881 * <pre> 882 * newCreateRequest("users", "1", content); 883 * </pre> 884 * 885 * Is equivalent to: 886 * 887 * <pre> 888 * newCreateRequest("users", content).setNewResourceId("1"); 889 * </pre> 890 * 891 * Except that the resource ID is already URL encoded in the second form. 892 * 893 * @param resourceContainer 894 * The URL-encoded path of the resource container beneath which 895 * the new resource should be created. 896 * @param newResourceId 897 * The URL decoded client provided ID of the resource to be 898 * created, or {@code null} if the server should be responsible 899 * for generating the resource ID. 900 * @param content 901 * The JSON content. 902 * @return The new create request. 903 */ 904 public static CreateRequest newCreateRequest(final String resourceContainer, 905 final String newResourceId, final JsonValue content) { 906 return newCreateRequest(resourceContainer, content).setNewResourceId(newResourceId); 907 } 908 909 /** 910 * Returns a new create request with the provided resource path, new 911 * resource ID, and JSON content. 912 * 913 * @param resourceContainer 914 * The parsed path of the resource container beneath which the 915 * new resource should be created. 916 * @param newResourceId 917 * The URL decoded client provided ID of the resource to be 918 * created, or {@code null} if the server should be responsible 919 * for generating the resource ID. 920 * @param content 921 * The JSON content. 922 * @return The new create request. 923 */ 924 public static CreateRequest newCreateRequest(final ResourcePath resourceContainer, 925 final String newResourceId, final JsonValue content) { 926 return newCreateRequest(resourceContainer, content).setNewResourceId(newResourceId); 927 } 928 929 /** 930 * Returns a new delete request with the provided resource path. Invoking 931 * this method as follows: 932 * 933 * <pre> 934 * newDeleteRequest("users/1"); 935 * </pre> 936 * 937 * Is equivalent to: 938 * 939 * <pre> 940 * newDeleteRequest("users", "1"); 941 * </pre> 942 * 943 * Except that the resource ID is already URL encoded in the first form. 944 * 945 * @param resourcePath 946 * The URL-encoded resource path. 947 * @return The new delete request. 948 */ 949 public static DeleteRequest newDeleteRequest(final String resourcePath) { 950 return new DeleteRequestImpl().setResourcePath(resourcePath); 951 } 952 953 /** 954 * Returns a new delete request with the provided resource path. 955 * 956 * @param resourcePath 957 * The parsed resource path. 958 * @return The new delete request. 959 */ 960 public static DeleteRequest newDeleteRequest(final ResourcePath resourcePath) { 961 return new DeleteRequestImpl().setResourcePath(resourcePath); 962 } 963 964 /** 965 * Returns a new delete request with the provided resource container path, 966 * and resource ID. Invoking this method as follows: 967 * 968 * <pre> 969 * newDeleteRequest("users", "1"); 970 * </pre> 971 * 972 * Is equivalent to: 973 * 974 * <pre> 975 * newDeleteRequest("users/1"); 976 * </pre> 977 * 978 * Except that the resource ID is already URL encoded in the second form. 979 * 980 * @param resourceContainer 981 * The URL-encoded path of the resource container. 982 * @param resourceId 983 * The URL decoded ID of the resource. 984 * @return The new delete request. 985 */ 986 public static DeleteRequest newDeleteRequest(final String resourceContainer, 987 final String resourceId) { 988 return newDeleteRequest(ResourcePath.valueOf(resourceContainer), resourceId); 989 } 990 991 /** 992 * Returns a new delete request with the provided resource container path, 993 * and resource ID. 994 * 995 * @param resourceContainer 996 * The parsed path of the resource container. 997 * @param resourceId 998 * The URL decoded ID of the resource. 999 * @return The new delete request. 1000 */ 1001 public static DeleteRequest newDeleteRequest(final ResourcePath resourceContainer, 1002 final String resourceId) { 1003 return newDeleteRequest(resourceContainer.child(resourceId)); 1004 } 1005 1006 /** 1007 * Returns a new patch request with the provided resource path and JSON 1008 * patch operations. Invoking this method as follows: 1009 * 1010 * <pre> 1011 * newPatchRequest("users/1", operations); 1012 * </pre> 1013 * 1014 * Is equivalent to: 1015 * 1016 * <pre> 1017 * newPatchRequest("users", "1", operations); 1018 * </pre> 1019 * 1020 * Except that the resource ID is already URL encoded in the first form. 1021 * 1022 * @param resourcePath 1023 * The URL-encoded resource path. 1024 * @param operations 1025 * The JSON patch operations. 1026 * @return The new patch request. 1027 */ 1028 public static PatchRequest newPatchRequest(final String resourcePath, 1029 final PatchOperation... operations) { 1030 return new PatchRequestImpl().setResourcePath(resourcePath).addPatchOperation(operations); 1031 } 1032 1033 /** 1034 * Returns a new patch request with the provided resource path and JSON 1035 * patch operations. 1036 * 1037 * @param resourcePath 1038 * The parsed resource path. 1039 * @param operations 1040 * The JSON patch operations. 1041 * @return The new patch request. 1042 */ 1043 public static PatchRequest newPatchRequest(final ResourcePath resourcePath, 1044 final PatchOperation... operations) { 1045 return new PatchRequestImpl().setResourcePath(resourcePath).addPatchOperation(operations); 1046 } 1047 1048 /** 1049 * Returns a new patch request with the provided resource container path, 1050 * resource ID, and JSON patch operations. Invoking this method as follows: 1051 * 1052 * <pre> 1053 * newPatchRequest("users", "1", operations); 1054 * </pre> 1055 * 1056 * Is equivalent to: 1057 * 1058 * <pre> 1059 * newPatchRequest("users/1", operations); 1060 * </pre> 1061 * 1062 * Except that the resource ID is already URL encoded in the second form. 1063 * 1064 * @param resourceContainer 1065 * The URL-encoded path of the resource container. 1066 * @param resourceId 1067 * The URL decoded ID of the resource. 1068 * @param operations 1069 * The JSON patch operations. 1070 * @return The new patch request. 1071 */ 1072 public static PatchRequest newPatchRequest(final String resourceContainer, 1073 final String resourceId, final PatchOperation... operations) { 1074 return newPatchRequest(ResourcePath.valueOf(resourceContainer), resourceId, operations); 1075 } 1076 1077 /** 1078 * Returns a new patch request with the provided resource container path, 1079 * resource ID, and JSON patch operations. 1080 * 1081 * @param resourceContainer 1082 * The parsed path of the resource container. 1083 * @param resourceId 1084 * The URL decoded ID of the resource. 1085 * @param operations 1086 * The JSON patch operations. 1087 * @return The new patch request. 1088 */ 1089 public static PatchRequest newPatchRequest(final ResourcePath resourceContainer, 1090 final String resourceId, final PatchOperation... operations) { 1091 return newPatchRequest(resourceContainer.child(resourceId), operations); 1092 } 1093 1094 /** 1095 * Returns a new query request with the provided resource container path. 1096 * Example: 1097 * 1098 * <pre> 1099 * newQueryRequest("users"); 1100 * </pre> 1101 * 1102 * @param resourceContainer 1103 * The URL-encoded path of the resource container. 1104 * @return The new query request. 1105 */ 1106 public static QueryRequest newQueryRequest(final String resourceContainer) { 1107 return new QueryRequestImpl().setResourcePath(resourceContainer); 1108 } 1109 1110 /** 1111 * Returns a new query request with the provided resource container path. 1112 * Example: 1113 * 1114 * <pre> 1115 * newQueryRequest(ResourcePath.valueOf("users")); 1116 * </pre> 1117 * 1118 * @param resourceContainer 1119 * The parsed path of the resource container. 1120 * @return The new query request. 1121 */ 1122 public static QueryRequest newQueryRequest(final ResourcePath resourceContainer) { 1123 return new QueryRequestImpl().setResourcePath(resourceContainer); 1124 } 1125 1126 /** 1127 * Returns a new read request with the provided resource path. Invoking this 1128 * method as follows: 1129 * 1130 * <pre> 1131 * newReadRequest("users/1"); 1132 * </pre> 1133 * 1134 * Is equivalent to: 1135 * 1136 * <pre> 1137 * newReadRequest("users", "1"); 1138 * </pre> 1139 * 1140 * Except that the resource ID is already URL encoded in the first form. 1141 * 1142 * @param resourcePath 1143 * The URL-encoded resource path. 1144 * @return The new read request. 1145 */ 1146 public static ReadRequest newReadRequest(final String resourcePath) { 1147 return new ReadRequestImpl().setResourcePath(resourcePath); 1148 } 1149 1150 /** 1151 * Returns a new read request with the provided resource path. 1152 * 1153 * @param resourcePath 1154 * The parsed resource path. 1155 * @return The new read request. 1156 */ 1157 public static ReadRequest newReadRequest(final ResourcePath resourcePath) { 1158 return new ReadRequestImpl().setResourcePath(resourcePath); 1159 } 1160 1161 /** 1162 * Returns a new read request with the provided resource container path, and 1163 * resource ID. Invoking this method as follows: 1164 * 1165 * <pre> 1166 * newReadRequest("users", "1"); 1167 * </pre> 1168 * 1169 * Is equivalent to: 1170 * 1171 * <pre> 1172 * newReadRequest("users/1"); 1173 * </pre> 1174 * 1175 * Except that the resource ID is already URL encoded in the second form. 1176 * 1177 * @param resourceContainer 1178 * The URL-encoded path of the resource container. 1179 * @param resourceId 1180 * The URL decoded ID of the resource. 1181 * @return The new read request. 1182 */ 1183 public static ReadRequest newReadRequest(final String resourceContainer, final String resourceId) { 1184 return newReadRequest(ResourcePath.valueOf(resourceContainer), resourceId); 1185 } 1186 1187 /** 1188 * Returns a new read request with the provided resource container path, and 1189 * resource ID. 1190 * 1191 * @param resourceContainer 1192 * The parsed path of the resource container. 1193 * @param resourceId 1194 * The URL decoded ID of the resource. 1195 * @return The new read request. 1196 */ 1197 public static ReadRequest newReadRequest(final ResourcePath resourceContainer, 1198 final String resourceId) { 1199 return newReadRequest(resourceContainer.child(resourceId)); 1200 } 1201 1202 /** 1203 * Returns a new update request with the provided resource path and new JSON 1204 * content. Invoking this method as follows: 1205 * 1206 * <pre> 1207 * newUpdateRequest("users/1", newContent); 1208 * </pre> 1209 * 1210 * Is equivalent to: 1211 * 1212 * <pre> 1213 * newUpdateRequest("users", "1", newContent); 1214 * </pre> 1215 * 1216 * Except that the resource ID is already URL encoded in the first form. 1217 * 1218 * @param resourcePath 1219 * The URL-encoded resource path. 1220 * @param newContent 1221 * The new JSON content. 1222 * @return The new update request. 1223 */ 1224 public static UpdateRequest newUpdateRequest(final String resourcePath, 1225 final JsonValue newContent) { 1226 return new UpdateRequestImpl().setResourcePath(resourcePath).setContent(newContent); 1227 } 1228 1229 /** 1230 * Returns a new update request with the provided resource path and new JSON 1231 * content. 1232 * 1233 * @param resourcePath 1234 * The parsed resource path. 1235 * @param newContent 1236 * The new JSON content. 1237 * @return The new update request. 1238 */ 1239 public static UpdateRequest newUpdateRequest(final ResourcePath resourcePath, 1240 final JsonValue newContent) { 1241 return new UpdateRequestImpl().setResourcePath(resourcePath).setContent(newContent); 1242 } 1243 1244 /** 1245 * Returns a new update request with the provided resource container path, 1246 * resource ID, and new JSON content. Invoking this method as follows: 1247 * 1248 * <pre> 1249 * newUpdateRequest("users", "1", newContent); 1250 * </pre> 1251 * 1252 * Is equivalent to: 1253 * 1254 * <pre> 1255 * newUpdateRequest("users/1", newContent); 1256 * </pre> 1257 * 1258 * Except that the resource ID is already URL encoded in the second form. 1259 * 1260 * @param resourceContainer 1261 * The URL-encoded path of the resource container. 1262 * @param resourceId 1263 * The URL decoded ID of the resource. 1264 * @param newContent 1265 * The new JSON content. 1266 * @return The new update request. 1267 */ 1268 public static UpdateRequest newUpdateRequest(final String resourceContainer, 1269 final String resourceId, final JsonValue newContent) { 1270 return newUpdateRequest(ResourcePath.valueOf(resourceContainer), resourceId, newContent); 1271 } 1272 1273 /** 1274 * Returns a new update request with the provided resource container path, 1275 * resource ID, and new JSON content. 1276 * 1277 * @param resourceContainer 1278 * The parsed path of the resource container. 1279 * @param resourceId 1280 * The URL decoded ID of the resource. 1281 * @param newContent 1282 * The new JSON content. 1283 * @return The new update request. 1284 */ 1285 public static UpdateRequest newUpdateRequest(final ResourcePath resourceContainer, 1286 final String resourceId, final JsonValue newContent) { 1287 return newUpdateRequest(resourceContainer.child(resourceId), newContent); 1288 } 1289 1290 private static JsonValue copyJsonValue(final JsonValue value) { 1291 return value != null ? value.copy() : null; 1292 } 1293 1294 private static <T> T notNull(final T object) { 1295 if (object != null) { 1296 return object; 1297 } else { 1298 throw new NullPointerException(); 1299 } 1300 } 1301 1302 private Requests() { 1303 // Prevent instantiation. 1304 } 1305 1306 // TODO: unmodifiable 1307}