All Downloads are FREE. Search and download functionalities are using the official Maven repository.

juzu.impl.plugin.controller.ControllerResolver Maven / Gradle / Ivy

There is a newer version: 1.2.0
Show newest version
/*
 * Copyright 2013 eXo Platform SAS
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package juzu.impl.plugin.controller;

import juzu.request.Phase;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * Controller method resolution algorithm.
 * 

* Resolves a controller method for a specified set of parameter names. The algorithm attempts to resolve a single value * with the following algorithm: *

*

  • Filter the list of controllers, this is specific to the resolve method.
  • When no method is retained, * the null value is returned.
  • When several methods are retained the resulting list is sorted according * resolution order. If a first value is greater than all the others, this result is returned, otherwise a {@link * AmbiguousResolutionException} is thrown.
*

* The resolution order uses three criteria for comparing two methods in the context of the specified parameter * names. *

*

  1. The greater number of matched specified parameters.
  2. The lesser number of unmatched method * arguments.
  3. The lesser number of unmatched method parameters.
  4. The default controller class.
  5. *
* * @author Julien Viet */ public abstract class ControllerResolver { // todo : take in account multi valued parameters // todo : what happens with type conversion, somehow we should forbid m(String a) and m(int a) public abstract M[] getHandlers(); public abstract String getId(M method); public abstract Phase getPhase(M method); public abstract String getName(M method); public abstract boolean isDefault(M method); public final boolean isIndex(M method) { return isDefault(method) && "index".equals(getName(method)); } public abstract Collection getParameterNames(M method); private class Match implements Comparable { /** . */ final M method; /** . */ final int score1; /** . */ final int score2; /** . */ final int score3; /** . */ final int score4; Match(Set parameterNames, M method) { this.method = method; // The number of matched parameters HashSet a = new HashSet(parameterNames); a.retainAll(getParameterNames(method)); this.score1 = a.size(); // The number of unmatched arguments a = new HashSet(getParameterNames(method)); a.removeAll(parameterNames); this.score2 = a.size(); // The number of unmatched parameters a = new HashSet(parameterNames); a.removeAll(getParameterNames(method)); this.score3 = a.size(); // The default method this.score4 = isDefault(method) ? 0 : 1; } public int compareTo(Match o) { int delta = o.score1 - score1; if (delta == 0) { delta = score2 - o.score2; if (delta == 0) { delta = score3 - o.score3; if (delta == 0) { delta = score4 - o.score4; } } } return delta; } @Override public String toString() { return "Match[score1=" + score1 + ",score2=" + score2 + ",score3=" + score3 + ",score4=" + score4 + ",method=" + method + "]"; } } /** * A method matches the filter when it has the render phase and the name index. * * @param phase the phare to match * @param parameterNames the parameter names * @return the resolved controller method * @throws NullPointerException if the parameter names set is nul * @throws AmbiguousResolutionException * if more than a single result is found */ public final M resolve(Phase phase, Set parameterNames) throws NullPointerException, AmbiguousResolutionException { if (parameterNames == null) { throw new NullPointerException("No null parameter names accepted"); } // List matches = new ArrayList(); for (M method : getHandlers()) { if (getPhase(method) == phase) { if (phase == Phase.VIEW) { if (getName(method).equals("index")) { matches.add(new Match(parameterNames, method)); } } else { matches.add(new Match(parameterNames, method)); } } } // return select(matches); } /** * A method matches the filter when it matches the phase and the method id. * * @param phase the phrase * @param methodId the method id * @param parameterNames the parameter names * @return the resolved controller method * @throws NullPointerException if any parameter is nul * @throws AmbiguousResolutionException * if more than a single result is found */ public final M resolveMethod(Phase phase, String methodId, final Set parameterNames) throws NullPointerException, AmbiguousResolutionException { if (parameterNames == null) { throw new NullPointerException("No null parameter names accepted"); } if (phase == null) { throw new NullPointerException("Phase parameter cannot be null"); } // List matches = new ArrayList(); for (M method : getHandlers()) { if (getPhase(method) == phase && (methodId == null || methodId.equals(getId(method)))) { matches.add(new Match(parameterNames, method)); } } // return select(matches); } /** * A method matches the filter when it matches the phase and the method id. * * @param phase the phrase * @param methodId the method id * @param parameterNames the parameter names * @return the resolved controller method * @throws NullPointerException if any parameter is nul * @throws AmbiguousResolutionException * if more than a single result is found */ public final List resolveMethods(Phase phase, String methodId, final Set parameterNames) throws NullPointerException, AmbiguousResolutionException { if (parameterNames == null) { throw new NullPointerException("No null parameter names accepted"); } if (phase == null) { throw new NullPointerException("Phase parameter cannot be null"); } // List matches = new ArrayList(); for (M method : getHandlers()) { if (getPhase(method) == phase && (methodId == null || methodId.equals(getId(method)))) { matches.add(new Match(parameterNames, method)); } } // Collections.sort(matches); ArrayList methods = new ArrayList(matches.size()); for (Match match : matches) { methods.add(match.method); } // return methods; } /** * A method matches the filter when it matches the type name, the method name and contains all the parameters. * * @param typeName the optional type name * @param methodName the method name * @param parameterNames the parameter names * @return the resolved controller method * @throws NullPointerException if the methodName or parameterNames argument is null * @throws AmbiguousResolutionException * if more than a single result is found */ public M resolve(String typeName, String methodName, Set parameterNames) throws NullPointerException, AmbiguousResolutionException { if (parameterNames == null) { throw new NullPointerException("No null parameter names accepted"); } if (methodName == null) { throw new NullPointerException("Phase parameter cannot be null"); } // List matches = new ArrayList(); for (M method : getHandlers()) { if (getParameterNames(method).containsAll(parameterNames)) { if (typeName == null) { if (getName(method).equals(methodName)) { matches.add(new Match(parameterNames, method)); } } else { String id = typeName + "." + methodName; if (getId(method).equals(id)) { matches.add(new Match(parameterNames, method)); } } } } // return select(matches); } private M select(List matches) throws AmbiguousResolutionException { M found = null; if (matches.size() > 0) { Collections.sort(matches); Match first = matches.get(0); if (matches.size() > 1) { Match second = matches.get(1); if (first.compareTo(second) == 0) { throw new AmbiguousResolutionException("Two methods satisfies the index criteria: " + first.method + " and " + second.method); } } found = first.method; } return found; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy