Hi Marcus,

I send you a sample Router class that mix two logics of routing :
- the first one is classically based on the URIs (i.e. "/internal/kb.portal" is not the same than "/internal/blabla") - the second one is based on the query parameters values (you can extend it to the body)


At the Application level in the "createRoot" method, instantiate the new QueryRouter and declare all your routes without the query part. For each added Route, declare also all variables with the required value as follow.
           @Override
           public Restlet createRoot() {
               Router router = new QueryRouter(getContext());
               Restlet restletLogon = new Restlet() {
                   @Override
                   public void handle(Request request, Response response) {
response.setEntity(new StringRepresentation("OK - Logon."));
                       response.setStatus(Status.SUCCESS_OK);
                   }
               };

               Restlet restletLogout = new Restlet() {
                   @Override
                   public void handle(Request request, Response response) {
response.setEntity(new StringRepresentation("OK - Logout."));
                       response.setStatus(Status.SUCCESS_OK);
                   }
               };

               Route logonRoute = router
                       .attach("/internal/kb.portal", restletLogon);
Map<String, Variable> logonVariables = logonRoute.getTemplate()
                       .getVariables();
               // Take care of using the same query parameter names
               logonVariables.put("_pageLabel", new Variable(
                       Variable.TYPE_URI_QUERY, "LOG", true, true));
               logonVariables.put("_actionOverride", new Variable(
                       Variable.TYPE_URI_QUERY,
                       "/portlet/internal/logon/logOn", true, true));

Route logoutRoute = router.attach("/internal/kb.portal", restletLogout);
               Map<String, Variable> logoutVariables = logoutRoute
                       .getTemplate().getVariables();
               // Take care of using the same query parameter names
               logoutVariables.put("_pageLabel", new Variable(
                       Variable.TYPE_URI_QUERY, "LOG", true, true));
               logoutVariables.put("_actionOverride", new Variable(
                       Variable.TYPE_URI_QUERY,
                       "/portlet/internal/logon/logOut", true, true));

               return router;
           }


I hope it will help you.

Best regards,
Thierry Boileau

All,

I am considering using Restlet to code up a simulator of an external
website and would appreciate some comments / help. The problem is that
the external URLs are ugly and not RESTian at all, see the examples
below. Does this preclude me from using Restlet in the first place as
I I've read the router doesn't take the query part of the URL into
account? I've looked through the tutorial and I've taken a quick look
at the source for Template and Variable but I haven't yet figured out
how the router matching/scoring works.

In the case of each example URL below, there may be additional
parameters that aren't relevant to the routing in both the POST and
GET URLs. The POST URLs will also have form-url-encoded parameters in
the body.

Example URLs (and desired mappings)
POST 
/internal/kb.portal?_pageLabel=LOG&_actionOverride=/portlet/internal/logon/logOn
--> Logon resource
POST 
/internal/kb.portal?_pageLabel=LOG&_actionOverride=/portlet/internal/logOff/logOff
--> Logoff resource
POST 
/internal/kb.portal?_pageLabel=SCH&_actionOverride=/portlet/internal/search/prepare
--> Search resource

GET 
/internal/kb.portal?_pageLabel=VIEW&_actionOverride=/portlet/internal/order/summary
--> OrderSummary resource
GET 
/internal/kb.portal?_pageLabel=VIEW&_actionOverride=/portlet/internal/order/history
--> OrderHistory resource
GET 
/internal/kb.portal?_pageLabel=VIEW&_actionOverride=/portlet/internal/order/payment
--> OrderPayments resource

Example code (that doesn't work at present ... with all the routes
above configured, all requests are routed to the last resource to be
attached):
<code>
        Router router = new Router(getContext());
        Route logonRoute =
router.attach("/internal/kb.portal?_pageLabel={page}&_actionOverride={action}&{other}",
resources.Logon.class);
        Map<String, Variable> logonVariables =
logonRoute.getTemplate().getVariables();
        logonVariables.put("page", new
Variable(Variable.TYPE_URI_QUERY, "LOG", true, true)); // required,
fixed
        logonVariables.put("action", new
Variable(Variable.TYPE_URI_QUERY, "/portlet/internal/logon/logOn",
true, true)); // required, fixed, decode, encode
        ...
</code>

So, can it be done with Restlet?

Thanks,
redentis

package routerQuery;

import java.util.Iterator;

import org.restlet.Context;
import org.restlet.Route;
import org.restlet.Router;
import org.restlet.data.Form;
import org.restlet.data.Request;
import org.restlet.data.Response;
import org.restlet.util.Variable;

public class QueryRouter extends Router {

    public QueryRouter(Context context) {
        super(context);
        // Allows you to customize the routing logic.
        setRoutingMode(Router.CUSTOM);
        // Allows to calculate the score of all routes without taking into
        // account the query part
        setDefaultMatchQuery(false);
    }

    /**
     * Mix the logic based on URI (except the query part) and the logic based on
     * query parameters.
     */
    @Override
    protected Route getCustom(Request request, Response response) {
        Form form = request.getResourceRef().getQueryAsForm();

        Route result = null;

        float bestScore = 0F;
        float score;

        for (Route current : getRoutes()) {
            // Logic based on the beginning of the route (i.e. all before the
            // query string)
            score = current.score(request, response);
            if ((score > bestScore)) {

                // Add the logic based on the variables values.
                // Check that all the variables values are correct
                boolean fit = true;
                for (Iterator<String> iterator = current.getTemplate()
                        .getVariables().keySet().iterator(); iterator.hasNext()
                        && fit;) {
                    String variableName = iterator.next();
                    Variable variable = current.getTemplate().getVariables()
                            .get(variableName);
                    String formValue = form.getFirstValue(variableName);
                    fit = (formValue != null && formValue.equals(variable
                            .getDefaultValue()));
                }

                if (fit) {
                    bestScore = score;
                    result = current;
                }
            }
        }

        return result;
    }
}

Reply via email to