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 2014-2015 ForgeRock AS.
015 */
016
017package org.forgerock.json.resource.examples;
018
019import static org.forgerock.json.resource.Responses.newResourceResponse;
020import static org.forgerock.json.resource.examples.DemoUtils.ctx;
021import static org.forgerock.json.resource.examples.DemoUtils.log;
022import static org.forgerock.util.promise.Promises.newResultPromise;
023
024import java.util.Collections;
025
026import org.forgerock.services.context.Context;
027import org.forgerock.json.JsonValue;
028import org.forgerock.json.resource.AbstractRequestHandler;
029import org.forgerock.json.resource.Connection;
030import org.forgerock.json.resource.ReadRequest;
031import org.forgerock.json.resource.RequestHandler;
032import org.forgerock.json.resource.Requests;
033import org.forgerock.json.resource.ResourceException;
034import org.forgerock.json.resource.ResourcePath;
035import org.forgerock.json.resource.ResourceResponse;
036import org.forgerock.json.resource.Resources;
037import org.forgerock.util.promise.Promise;
038
039/**
040 * An example illustrating how you can route realms / sub-realm requests using
041 * simple hand-crafted routing. Resource URLs are of the form
042 * {@code realm0/realm1/.../realmx/users/id}. For simple resource hierarchies
043 * this approach is simpler than using dynamic routing.
044 */
045public final class SimpleRealmDemo {
046    /**
047     * Main application.
048     *
049     * @param args
050     *            No arguments required.
051     * @throws ResourceException
052     *             If an unexpected error occurred.
053     */
054    public static void main(final String... args) throws ResourceException {
055        final RequestHandler rootRealm = simpleRouter();
056        final Connection c = Resources.newInternalConnection(rootRealm);
057
058        // Realm = [], Collection = users, Resource = alice
059        c.read(ctx(), Requests.newReadRequest("users/alice"));
060
061        // Realm = [], Collection = groups, Resource = administrators
062        c.read(ctx(), Requests.newReadRequest("groups/administrators"));
063
064        // Realm = [a], Collection = users, Resource = alice
065        c.read(ctx(), Requests.newReadRequest("a/users/alice"));
066
067        // Realm = [a, b], Collection = users, Resource = alice
068        c.read(ctx(), Requests.newReadRequest("a/b/users/alice"));
069    }
070
071    /**
072     * Returns a request handler which will handle requests to a sub-realm.
073     *
074     * @return A request handler which will handle requests to a sub-realm.
075     */
076    private static RequestHandler simpleRouter() {
077        return new AbstractRequestHandler() {
078            @Override
079            public Promise<ResourceResponse, ResourceException> handleRead(final Context context,
080                    final ReadRequest request) {
081                final ResourcePath name = request.getResourcePathObject();
082                final int size = name.size();
083                if (size == 0) {
084                    log("Reading root");
085                } else if (name.leaf().equals("users")) {
086                    log("Reading users container in " + name.subSequence(0, size - 1));
087                } else if (name.leaf().equals("groups")) {
088                    log("Reading groups container in " + name.subSequence(0, size - 1));
089                } else if (size > 1) {
090                    if (name.get(size - 2).equals("users")) {
091                        read("user", name);
092                    } else if (name.get(size - 2).equals("groups")) {
093                        read("group", name);
094                    } else {
095                        log("Reading realm " + name);
096                    }
097                } else {
098                    log("Reading realm " + name);
099                }
100
101                final JsonValue content =
102                        new JsonValue(Collections.singletonMap("id", (Object) name.leaf()));
103                return newResultPromise(newResourceResponse(name.leaf(), "1", content));
104            }
105        };
106    }
107
108    private static void read(final String type, final ResourcePath path) {
109        log("Reading " + type);
110        log("    resource ID : " + path.leaf());
111        log("    realm path  : " + path.subSequence(0, path.size() - 2));
112    }
113
114    private SimpleRealmDemo() {
115        // Prevent instantiation.
116    }
117}