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-2016 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 private static final class ApiRequestImpl extends AbstractRequestImpl<Request> { 666 private ApiRequestImpl() { 667 // nothing to do 668 } 669 670 private ApiRequestImpl(ApiRequestImpl request) { 671 super(request); 672 } 673 674 @Override 675 protected Request getThis() { 676 return this; 677 } 678 679 @Override 680 public <R, P> R accept(RequestVisitor<R, P> v, P p) { 681 throw new UnsupportedOperationException(); 682 } 683 684 @Override 685 public RequestType getRequestType() { 686 return RequestType.API; 687 } 688 } 689 690 /** 691 * Returns a copy of the provided action request. 692 * 693 * @param request 694 * The action request to be copied. 695 * @return The action request copy. 696 */ 697 public static ActionRequest copyOfActionRequest(final ActionRequest request) { 698 return new ActionRequestImpl(request); 699 } 700 701 /** 702 * Returns a copy of the provided create request. 703 * 704 * @param request 705 * The create request to be copied. 706 * @return The create request copy. 707 */ 708 public static CreateRequest copyOfCreateRequest(final CreateRequest request) { 709 return new CreateRequestImpl(request); 710 } 711 712 /** 713 * Returns a copy of the provided delete request. 714 * 715 * @param request 716 * The delete request to be copied. 717 * @return The delete request copy. 718 */ 719 public static DeleteRequest copyOfDeleteRequest(final DeleteRequest request) { 720 return new DeleteRequestImpl(request); 721 } 722 723 /** 724 * Returns a copy of the provided patch request. 725 * 726 * @param request 727 * The patch request to be copied. 728 * @return The patch request copy. 729 */ 730 public static PatchRequest copyOfPatchRequest(final PatchRequest request) { 731 return new PatchRequestImpl(request); 732 } 733 734 /** 735 * Returns a copy of the provided query request. 736 * 737 * @param request 738 * The query request to be copied. 739 * @return The query request copy. 740 */ 741 public static QueryRequest copyOfQueryRequest(final QueryRequest request) { 742 return new QueryRequestImpl(request); 743 } 744 745 /** 746 * Returns a copy of the provided read request. 747 * 748 * @param request 749 * The read request to be copied. 750 * @return The read request copy. 751 */ 752 public static ReadRequest copyOfReadRequest(final ReadRequest request) { 753 return new ReadRequestImpl(request); 754 } 755 756 /** 757 * Returns a copy of the provided update request. 758 * 759 * @param request 760 * The update request to be copied. 761 * @return The update request copy. 762 */ 763 public static UpdateRequest copyOfUpdateRequest(final UpdateRequest request) { 764 return new UpdateRequestImpl(request); 765 } 766 767 /** 768 * Returns a copy of the provided api request. 769 * 770 * @param request 771 * The api request to be copied. 772 * @return The api request copy. 773 */ 774 public static Request copyOfApiRequest(final Request request) { 775 return new ApiRequestImpl((ApiRequestImpl) request); 776 } 777 778 /** 779 * Returns a new action request with the provided resource path and action 780 * ID. Invoking this method as follows: 781 * 782 * <pre> 783 * newActionRequest("users/1", actionId); 784 * </pre> 785 * 786 * Is equivalent to: 787 * 788 * <pre> 789 * newActionRequest("users", "1", actionId); 790 * </pre> 791 * 792 * Except that the resource ID is already URL encoded in the first form. 793 * 794 * @param resourcePath 795 * The URL-encoded resource path. 796 * @param actionId 797 * The action ID. 798 * @return The new action request. 799 */ 800 public static ActionRequest newActionRequest(final String resourcePath, final String actionId) { 801 return new ActionRequestImpl().setResourcePath(resourcePath).setAction(actionId); 802 } 803 804 /** 805 * Returns a new action request with the provided resource path and action 806 * ID. 807 * 808 * @param resourcePath 809 * The parsed resource path. 810 * @param actionId 811 * The action ID. 812 * @return The new action request. 813 */ 814 public static ActionRequest newActionRequest(final ResourcePath resourcePath, 815 final String actionId) { 816 return new ActionRequestImpl().setResourcePath(resourcePath).setAction(actionId); 817 } 818 819 /** 820 * Returns a new action request with the provided resource container path, 821 * resource ID, and action ID. Invoking this method as follows: 822 * 823 * <pre> 824 * newActionRequest("users", "1", "someAction"); 825 * </pre> 826 * 827 * Is equivalent to: 828 * 829 * <pre> 830 * newActionRequest("users/1", "someAction"); 831 * </pre> 832 * 833 * Except that the resource ID is already URL encoded in the second form. 834 * 835 * @param resourceContainer 836 * The URL-encoded path of the resource container. 837 * @param resourceId 838 * The URL decoded ID of the resource. 839 * @param actionId 840 * The action ID. 841 * @return The new action request. 842 */ 843 public static ActionRequest newActionRequest(final String resourceContainer, 844 final String resourceId, final String actionId) { 845 return newActionRequest(ResourcePath.valueOf(resourceContainer), resourceId, actionId); 846 } 847 848 /** 849 * Returns a new action request with the provided resource container path, 850 * resource ID, and action ID. 851 * 852 * @param resourceContainer 853 * The parsed path of the resource container. 854 * @param resourceId 855 * The URL decoded ID of the resource. 856 * @param actionId 857 * The action ID. 858 * @return The new action request. 859 */ 860 public static ActionRequest newActionRequest(final ResourcePath resourceContainer, 861 final String resourceId, final String actionId) { 862 return newActionRequest(resourceContainer.child(resourceId), actionId); 863 } 864 865 /** 866 * Returns a new create request with the provided resource path, and JSON 867 * content. The create request will have a {@code null} new resource ID, 868 * indicating that the server will be responsible for generating the ID of 869 * the new resource. Invoking this method as follows: 870 * 871 * <pre> 872 * newCreateRequest("users/1", content); 873 * </pre> 874 * 875 * Is equivalent to: 876 * 877 * <pre> 878 * newCreateRequest("users", "1", content); 879 * </pre> 880 * 881 * Except that the resource ID is already URL encoded in the first form. 882 * 883 * @param resourceContainer 884 * The URL-encoded path of the resource container beneath which the new 885 * resource should be created. 886 * @param content 887 * The JSON content. 888 * @return The new create request. 889 */ 890 public static CreateRequest newCreateRequest(final String resourceContainer, 891 final JsonValue content) { 892 return new CreateRequestImpl().setResourcePath(resourceContainer).setContent(content); 893 } 894 895 /** 896 * Returns a new create request with the provided resource path, and JSON 897 * content. The create request will have a {@code null} new resource ID, 898 * indicating that the server will be responsible for generating the ID of 899 * the new resource. 900 * 901 * @param resourceContainer 902 * The parsed path of the resource container beneath which the 903 * new resource should be created. 904 * @param content 905 * The JSON content. 906 * @return The new create request. 907 */ 908 public static CreateRequest newCreateRequest(final ResourcePath resourceContainer, 909 final JsonValue content) { 910 return new CreateRequestImpl().setResourcePath(resourceContainer).setContent(content); 911 } 912 913 /** 914 * Returns a new create request with the provided resource path, new 915 * resource ID, and JSON content. Invoking this method as follows: 916 * 917 * <pre> 918 * newCreateRequest("users", "1", content); 919 * </pre> 920 * 921 * Is equivalent to: 922 * 923 * <pre> 924 * newCreateRequest("users", content).setNewResourceId("1"); 925 * </pre> 926 * 927 * Except that the resource ID is already URL encoded in the second form. 928 * 929 * @param resourceContainer 930 * The URL-encoded path of the resource container beneath which 931 * the new resource should be created. 932 * @param newResourceId 933 * The URL decoded client provided ID of the resource to be 934 * created, or {@code null} if the server should be responsible 935 * for generating the resource ID. 936 * @param content 937 * The JSON content. 938 * @return The new create request. 939 */ 940 public static CreateRequest newCreateRequest(final String resourceContainer, 941 final String newResourceId, final JsonValue content) { 942 return newCreateRequest(resourceContainer, content).setNewResourceId(newResourceId); 943 } 944 945 /** 946 * Returns a new create request with the provided resource path, new 947 * resource ID, and JSON content. 948 * 949 * @param resourceContainer 950 * The parsed path of the resource container beneath which the 951 * new resource should be created. 952 * @param newResourceId 953 * The URL decoded client provided ID of the resource to be 954 * created, or {@code null} if the server should be responsible 955 * for generating the resource ID. 956 * @param content 957 * The JSON content. 958 * @return The new create request. 959 */ 960 public static CreateRequest newCreateRequest(final ResourcePath resourceContainer, 961 final String newResourceId, final JsonValue content) { 962 return newCreateRequest(resourceContainer, content).setNewResourceId(newResourceId); 963 } 964 965 /** 966 * Returns a new delete request with the provided resource path. Invoking 967 * this method as follows: 968 * 969 * <pre> 970 * newDeleteRequest("users/1"); 971 * </pre> 972 * 973 * Is equivalent to: 974 * 975 * <pre> 976 * newDeleteRequest("users", "1"); 977 * </pre> 978 * 979 * Except that the resource ID is already URL encoded in the first form. 980 * 981 * @param resourcePath 982 * The URL-encoded resource path. 983 * @return The new delete request. 984 */ 985 public static DeleteRequest newDeleteRequest(final String resourcePath) { 986 return new DeleteRequestImpl().setResourcePath(resourcePath); 987 } 988 989 /** 990 * Returns a new delete request with the provided resource path. 991 * 992 * @param resourcePath 993 * The parsed resource path. 994 * @return The new delete request. 995 */ 996 public static DeleteRequest newDeleteRequest(final ResourcePath resourcePath) { 997 return new DeleteRequestImpl().setResourcePath(resourcePath); 998 } 999 1000 /** 1001 * Returns a new delete request with the provided resource container path, 1002 * and resource ID. Invoking this method as follows: 1003 * 1004 * <pre> 1005 * newDeleteRequest("users", "1"); 1006 * </pre> 1007 * 1008 * Is equivalent to: 1009 * 1010 * <pre> 1011 * newDeleteRequest("users/1"); 1012 * </pre> 1013 * 1014 * Except that the resource ID is already URL encoded in the second form. 1015 * 1016 * @param resourceContainer 1017 * The URL-encoded path of the resource container. 1018 * @param resourceId 1019 * The URL decoded ID of the resource. 1020 * @return The new delete request. 1021 */ 1022 public static DeleteRequest newDeleteRequest(final String resourceContainer, 1023 final String resourceId) { 1024 return newDeleteRequest(ResourcePath.valueOf(resourceContainer), resourceId); 1025 } 1026 1027 /** 1028 * Returns a new delete request with the provided resource container path, 1029 * and resource ID. 1030 * 1031 * @param resourceContainer 1032 * The parsed path of the resource container. 1033 * @param resourceId 1034 * The URL decoded ID of the resource. 1035 * @return The new delete request. 1036 */ 1037 public static DeleteRequest newDeleteRequest(final ResourcePath resourceContainer, 1038 final String resourceId) { 1039 return newDeleteRequest(resourceContainer.child(resourceId)); 1040 } 1041 1042 /** 1043 * Returns a new patch request with the provided resource path and JSON 1044 * patch operations. Invoking this method as follows: 1045 * 1046 * <pre> 1047 * newPatchRequest("users/1", operations); 1048 * </pre> 1049 * 1050 * Is equivalent to: 1051 * 1052 * <pre> 1053 * newPatchRequest("users", "1", operations); 1054 * </pre> 1055 * 1056 * Except that the resource ID is already URL encoded in the first form. 1057 * 1058 * @param resourcePath 1059 * The URL-encoded resource path. 1060 * @param operations 1061 * The JSON patch operations. 1062 * @return The new patch request. 1063 */ 1064 public static PatchRequest newPatchRequest(final String resourcePath, 1065 final PatchOperation... operations) { 1066 return new PatchRequestImpl().setResourcePath(resourcePath).addPatchOperation(operations); 1067 } 1068 1069 /** 1070 * Returns a new patch request with the provided resource path and JSON 1071 * patch operations. 1072 * 1073 * @param resourcePath 1074 * The parsed resource path. 1075 * @param operations 1076 * The JSON patch operations. 1077 * @return The new patch request. 1078 */ 1079 public static PatchRequest newPatchRequest(final ResourcePath resourcePath, 1080 final PatchOperation... operations) { 1081 return new PatchRequestImpl().setResourcePath(resourcePath).addPatchOperation(operations); 1082 } 1083 1084 /** 1085 * Returns a new patch request with the provided resource container path, 1086 * resource ID, and JSON patch operations. Invoking this method as follows: 1087 * 1088 * <pre> 1089 * newPatchRequest("users", "1", operations); 1090 * </pre> 1091 * 1092 * Is equivalent to: 1093 * 1094 * <pre> 1095 * newPatchRequest("users/1", operations); 1096 * </pre> 1097 * 1098 * Except that the resource ID is already URL encoded in the second form. 1099 * 1100 * @param resourceContainer 1101 * The URL-encoded path of the resource container. 1102 * @param resourceId 1103 * The URL decoded ID of the resource. 1104 * @param operations 1105 * The JSON patch operations. 1106 * @return The new patch request. 1107 */ 1108 public static PatchRequest newPatchRequest(final String resourceContainer, 1109 final String resourceId, final PatchOperation... operations) { 1110 return newPatchRequest(ResourcePath.valueOf(resourceContainer), resourceId, operations); 1111 } 1112 1113 /** 1114 * Returns a new patch request with the provided resource container path, 1115 * resource ID, and JSON patch operations. 1116 * 1117 * @param resourceContainer 1118 * The parsed path of the resource container. 1119 * @param resourceId 1120 * The URL decoded ID of the resource. 1121 * @param operations 1122 * The JSON patch operations. 1123 * @return The new patch request. 1124 */ 1125 public static PatchRequest newPatchRequest(final ResourcePath resourceContainer, 1126 final String resourceId, final PatchOperation... operations) { 1127 return newPatchRequest(resourceContainer.child(resourceId), operations); 1128 } 1129 1130 /** 1131 * Returns a new query request with the provided resource container path. 1132 * Example: 1133 * 1134 * <pre> 1135 * newQueryRequest("users"); 1136 * </pre> 1137 * 1138 * @param resourceContainer 1139 * The URL-encoded path of the resource container. 1140 * @return The new query request. 1141 */ 1142 public static QueryRequest newQueryRequest(final String resourceContainer) { 1143 return new QueryRequestImpl().setResourcePath(resourceContainer); 1144 } 1145 1146 /** 1147 * Returns a new query request with the provided resource container path. 1148 * Example: 1149 * 1150 * <pre> 1151 * newQueryRequest(ResourcePath.valueOf("users")); 1152 * </pre> 1153 * 1154 * @param resourceContainer 1155 * The parsed path of the resource container. 1156 * @return The new query request. 1157 */ 1158 public static QueryRequest newQueryRequest(final ResourcePath resourceContainer) { 1159 return new QueryRequestImpl().setResourcePath(resourceContainer); 1160 } 1161 1162 /** 1163 * Returns a new read request with the provided resource path. Invoking this 1164 * method as follows: 1165 * 1166 * <pre> 1167 * newReadRequest("users/1"); 1168 * </pre> 1169 * 1170 * Is equivalent to: 1171 * 1172 * <pre> 1173 * newReadRequest("users", "1"); 1174 * </pre> 1175 * 1176 * Except that the resource ID is already URL encoded in the first form. 1177 * 1178 * @param resourcePath 1179 * The URL-encoded resource path. 1180 * @return The new read request. 1181 */ 1182 public static ReadRequest newReadRequest(final String resourcePath) { 1183 return new ReadRequestImpl().setResourcePath(resourcePath); 1184 } 1185 1186 /** 1187 * Returns a new read request with the provided resource path. 1188 * 1189 * @param resourcePath 1190 * The parsed resource path. 1191 * @return The new read request. 1192 */ 1193 public static ReadRequest newReadRequest(final ResourcePath resourcePath) { 1194 return new ReadRequestImpl().setResourcePath(resourcePath); 1195 } 1196 1197 /** 1198 * Returns a new read request with the provided resource container path, and 1199 * resource ID. Invoking this method as follows: 1200 * 1201 * <pre> 1202 * newReadRequest("users", "1"); 1203 * </pre> 1204 * 1205 * Is equivalent to: 1206 * 1207 * <pre> 1208 * newReadRequest("users/1"); 1209 * </pre> 1210 * 1211 * Except that the resource ID is already URL encoded in the second form. 1212 * 1213 * @param resourceContainer 1214 * The URL-encoded path of the resource container. 1215 * @param resourceId 1216 * The URL decoded ID of the resource. 1217 * @return The new read request. 1218 */ 1219 public static ReadRequest newReadRequest(final String resourceContainer, final String resourceId) { 1220 return newReadRequest(ResourcePath.valueOf(resourceContainer), resourceId); 1221 } 1222 1223 /** 1224 * Returns a new read request with the provided resource container path, and 1225 * resource ID. 1226 * 1227 * @param resourceContainer 1228 * The parsed path of the resource container. 1229 * @param resourceId 1230 * The URL decoded ID of the resource. 1231 * @return The new read request. 1232 */ 1233 public static ReadRequest newReadRequest(final ResourcePath resourceContainer, 1234 final String resourceId) { 1235 return newReadRequest(resourceContainer.child(resourceId)); 1236 } 1237 1238 /** 1239 * Returns a new update request with the provided resource path and new JSON 1240 * content. Invoking this method as follows: 1241 * 1242 * <pre> 1243 * newUpdateRequest("users/1", newContent); 1244 * </pre> 1245 * 1246 * Is equivalent to: 1247 * 1248 * <pre> 1249 * newUpdateRequest("users", "1", newContent); 1250 * </pre> 1251 * 1252 * Except that the resource ID is already URL encoded in the first form. 1253 * 1254 * @param resourcePath 1255 * The URL-encoded resource path. 1256 * @param newContent 1257 * The new JSON content. 1258 * @return The new update request. 1259 */ 1260 public static UpdateRequest newUpdateRequest(final String resourcePath, 1261 final JsonValue newContent) { 1262 return new UpdateRequestImpl().setResourcePath(resourcePath).setContent(newContent); 1263 } 1264 1265 /** 1266 * Returns a new update request with the provided resource path and new JSON 1267 * content. 1268 * 1269 * @param resourcePath 1270 * The parsed resource path. 1271 * @param newContent 1272 * The new JSON content. 1273 * @return The new update request. 1274 */ 1275 public static UpdateRequest newUpdateRequest(final ResourcePath resourcePath, 1276 final JsonValue newContent) { 1277 return new UpdateRequestImpl().setResourcePath(resourcePath).setContent(newContent); 1278 } 1279 1280 /** 1281 * Returns a new update request with the provided resource container path, 1282 * resource ID, and new JSON content. Invoking this method as follows: 1283 * 1284 * <pre> 1285 * newUpdateRequest("users", "1", newContent); 1286 * </pre> 1287 * 1288 * Is equivalent to: 1289 * 1290 * <pre> 1291 * newUpdateRequest("users/1", newContent); 1292 * </pre> 1293 * 1294 * Except that the resource ID is already URL encoded in the second form. 1295 * 1296 * @param resourceContainer 1297 * The URL-encoded path of the resource container. 1298 * @param resourceId 1299 * The URL decoded ID of the resource. 1300 * @param newContent 1301 * The new JSON content. 1302 * @return The new update request. 1303 */ 1304 public static UpdateRequest newUpdateRequest(final String resourceContainer, 1305 final String resourceId, final JsonValue newContent) { 1306 return newUpdateRequest(ResourcePath.valueOf(resourceContainer), resourceId, newContent); 1307 } 1308 1309 /** 1310 * Returns a new update request with the provided resource container path, 1311 * resource ID, and new JSON content. 1312 * 1313 * @param resourceContainer 1314 * The parsed path of the resource container. 1315 * @param resourceId 1316 * The URL decoded ID of the resource. 1317 * @param newContent 1318 * The new JSON content. 1319 * @return The new update request. 1320 */ 1321 public static UpdateRequest newUpdateRequest(final ResourcePath resourceContainer, 1322 final String resourceId, final JsonValue newContent) { 1323 return newUpdateRequest(resourceContainer.child(resourceId), newContent); 1324 } 1325 1326 /** 1327 * Returns a new API request with the provided path. 1328 * @param path The path. 1329 * @return The request. 1330 */ 1331 public static Request newApiRequest(final ResourcePath path) { 1332 return new ApiRequestImpl().setResourcePath(path); 1333 } 1334 1335 private static JsonValue copyJsonValue(final JsonValue value) { 1336 return value != null ? value.copy() : null; 1337 } 1338 1339 private static <T> T notNull(final T object) { 1340 if (object != null) { 1341 return object; 1342 } else { 1343 throw new NullPointerException(); 1344 } 1345 } 1346 1347 private Requests() { 1348 // Prevent instantiation. 1349 } 1350 1351 // TODO: unmodifiable 1352}