public static ActionDefinition reverse(String action, Map<String, Object> args) { String encoding = Http.Response.current() == null ? Play.defaultWebEncoding : Http.Response.current().encoding; if (action.startsWith("controllers.")) { action = action.substring(12); } Map<String, Object> argsbackup = new HashMap<String, Object>(args); // Add routeArgs if (Scope.RouteArgs.current() != null) { for (String key : Scope.RouteArgs.current().data.keySet()) { if (!args.containsKey(key)) { args.put(key, Scope.RouteArgs.current().data.get(key)); } } } for (Route route : routes) { if (route.actionPattern != null) { Matcher matcher = route.actionPattern.matcher(action); if (matcher.matches()) { for (String group : route.actionArgs) { String v = matcher.group(group); if (v == null) { continue; } args.put(group, v.toLowerCase()); } List<String> inPathArgs = new ArrayList<String>(16); boolean allRequiredArgsAreHere = true; // les noms de parametres matchent ils ? for (Route.Arg arg : route.args) { inPathArgs.add(arg.name); Object value = args.get(arg.name); if (value == null) { // This is a hack for reverting on hostname that are a regex expression. // See [#344] for more into. This is not optimal and should retough. However, // it allows us to do things like {(.*}}.domain.com String host = route.host.replaceAll("\\{", "").replaceAll("\\}", ""); if (host.equals(arg.name) || host.matches(arg.name)) { args.remove(arg.name); route.host = Http.Request.current() == null ? "" : Http.Request.current().domain; break; } else { allRequiredArgsAreHere = false; break; } } else { if (value instanceof List<?>) { @SuppressWarnings("unchecked") List<Object> l = (List<Object>) value; value = l.get(0); } if (!value.toString().startsWith(":") && !arg.constraint.matches(value.toString())) { allRequiredArgsAreHere = false; break; } } } // les parametres codes en dur dans la route matchent-ils ? for (String staticKey : route.staticArgs.keySet()) { if (staticKey.equals("format")) { if (!(Http.Request.current() == null ? "" : Http.Request.current().format) .equals(route.staticArgs.get("format"))) { allRequiredArgsAreHere = false; break; } continue; // format is a special key } if (!args.containsKey(staticKey) || (args.get(staticKey) == null) || !args.get(staticKey).toString().equals(route.staticArgs.get(staticKey))) { allRequiredArgsAreHere = false; break; } } if (allRequiredArgsAreHere) { StringBuilder queryString = new StringBuilder(); String path = route.path; String host = route.host; if (path.endsWith("/?")) { path = path.substring(0, path.length() - 2); } for (Map.Entry<String, Object> entry : args.entrySet()) { String key = entry.getKey(); Object value = entry.getValue(); if (inPathArgs.contains(key) && value != null) { if (List.class.isAssignableFrom(value.getClass())) { @SuppressWarnings("unchecked") List<Object> vals = (List<Object>) value; path = path.replaceAll("\\{(<[^>]+>)?" + key + "\\}", vals.get(0).toString()) .replace("$", "\\$"); } else { path = path.replaceAll( "\\{(<[^>]+>)?" + key + "\\}", value .toString() .replace("$", "\\$") .replace("%3A", ":") .replace("%40", "@")); host = host.replaceAll( "\\{(<[^>]+>)?" + key + "\\}", value .toString() .replace("$", "\\$") .replace("%3A", ":") .replace("%40", "@")); } } else if (route.staticArgs.containsKey(key)) { // Do nothing -> The key is static } else if (Scope.RouteArgs.current() != null && Scope.RouteArgs.current().data.containsKey(key)) { // Do nothing -> The key is provided in RouteArgs and not used (see #447) } else if (value != null) { if (List.class.isAssignableFrom(value.getClass())) { @SuppressWarnings("unchecked") List<Object> vals = (List<Object>) value; for (Object object : vals) { try { queryString.append(URLEncoder.encode(key, encoding)); queryString.append("="); if (object.toString().startsWith(":")) { queryString.append(object.toString()); } else { queryString.append(URLEncoder.encode(object.toString() + "", encoding)); } queryString.append("&"); } catch (UnsupportedEncodingException ex) { } } } else if (value.getClass().equals(Default.class)) { // Skip defaults in queryString } else { try { queryString.append(URLEncoder.encode(key, encoding)); queryString.append("="); if (value.toString().startsWith(":")) { queryString.append(value.toString()); } else { queryString.append(URLEncoder.encode(value.toString() + "", encoding)); } queryString.append("&"); } catch (UnsupportedEncodingException ex) { } } } } String qs = queryString.toString(); if (qs.endsWith("&")) { qs = qs.substring(0, qs.length() - 1); } ActionDefinition actionDefinition = new ActionDefinition(); actionDefinition.url = qs.length() == 0 ? path : path + "?" + qs; actionDefinition.method = route.method == null || route.method.equals("*") ? "GET" : route.method.toUpperCase(); actionDefinition.star = "*".equals(route.method); actionDefinition.action = action; actionDefinition.args = argsbackup; actionDefinition.host = host; return actionDefinition; } } } } throw new NoRouteFoundException(action, args); }
public static void invoke(Http.Request request, Http.Response response) { Monitor monitor = null; try { resolve(request, response); Method actionMethod = request.invokedMethod; // 1. Prepare request params Scope.Params.current().__mergeWith(request.routeArgs); // add parameters from the URI query string String encoding = Http.Request.current().encoding; Scope.Params.current() ._mergeWith( UrlEncodedParser.parseQueryString( new ByteArrayInputStream(request.querystring.getBytes(encoding)))); // 2. Easy debugging ... if (Play.mode == Play.Mode.DEV) { Class<Controller> cclass = Controller.class; cclass.getDeclaredField("params").set(null, Scope.Params.current()); cclass.getDeclaredField("request").set(null, Http.Request.current()); cclass.getDeclaredField("response").set(null, Http.Response.current()); cclass.getDeclaredField("session").set(null, Scope.Session.current()); cclass.getDeclaredField("flash").set(null, Scope.Flash.current()); cclass.getDeclaredField("renderArgs").set(null, Scope.RenderArgs.current()); cclass.getDeclaredField("routeArgs").set(null, Scope.RouteArgs.current()); cclass.getDeclaredField("validation").set(null, Validation.current()); } ControllerInstrumentation.stopActionCall(); Play.pluginCollection.beforeActionInvocation(actionMethod); // Monitoring monitor = MonitorFactory.start(request.action + "()"); // 3. Invoke the action try { // @Before handleBefores(request); // Action Result actionResult = null; String cacheKey = null; // Check the cache (only for GET or HEAD) if ((request.method.equals("GET") || request.method.equals("HEAD")) && actionMethod.isAnnotationPresent(CacheFor.class)) { cacheKey = actionMethod.getAnnotation(CacheFor.class).id(); if ("".equals(cacheKey)) { cacheKey = "urlcache:" + request.url + request.querystring; } actionResult = (Result) play.cache.Cache.get(cacheKey); } if (actionResult == null) { ControllerInstrumentation.initActionCall(); try { inferResult(invokeControllerMethod(actionMethod)); } catch (Result result) { actionResult = result; // Cache it if needed if (cacheKey != null) { play.cache.Cache.set( cacheKey, actionResult, actionMethod.getAnnotation(CacheFor.class).value()); } } catch (InvocationTargetException ex) { // It's a Result ? (expected) if (ex.getTargetException() instanceof Result) { actionResult = (Result) ex.getTargetException(); // Cache it if needed if (cacheKey != null) { play.cache.Cache.set( cacheKey, actionResult, actionMethod.getAnnotation(CacheFor.class).value()); } } else { // @Catch Object[] args = new Object[] {ex.getTargetException()}; List<Method> catches = Java.findAllAnnotatedMethods(Controller.getControllerClass(), Catch.class); ControllerInstrumentation.stopActionCall(); for (Method mCatch : catches) { Class[] exceptions = mCatch.getAnnotation(Catch.class).value(); if (exceptions.length == 0) { exceptions = new Class[] {Exception.class}; } for (Class exception : exceptions) { if (exception.isInstance(args[0])) { mCatch.setAccessible(true); inferResult(invokeControllerMethod(mCatch, args)); break; } } } throw ex; } } } // @After handleAfters(request); monitor.stop(); monitor = null; // OK, re-throw the original action result if (actionResult != null) { throw actionResult; } throw new NoResult(); } catch (IllegalAccessException ex) { throw ex; } catch (IllegalArgumentException ex) { throw ex; } catch (InvocationTargetException ex) { // It's a Result ? (expected) if (ex.getTargetException() instanceof Result) { throw (Result) ex.getTargetException(); } // Re-throw the enclosed exception if (ex.getTargetException() instanceof PlayException) { throw (PlayException) ex.getTargetException(); } StackTraceElement element = PlayException.getInterestingStackTraceElement(ex.getTargetException()); if (element != null) { throw new JavaExecutionException( Play.classes.getApplicationClass(element.getClassName()), element.getLineNumber(), ex.getTargetException()); } throw new JavaExecutionException(Http.Request.current().action, ex); } } catch (Result result) { Play.pluginCollection.onActionInvocationResult(result); // OK there is a result to apply // Save session & flash scope now Scope.Session.current().save(); Scope.Flash.current().save(); result.apply(request, response); Play.pluginCollection.afterActionInvocation(); // @Finally handleFinallies(request, null); } catch (PlayException e) { handleFinallies(request, e); throw e; } catch (Throwable e) { handleFinallies(request, e); throw new UnexpectedException(e); } finally { Play.pluginCollection.onActionInvocationFinally(); if (monitor != null) { monitor.stop(); } } }