public static Object invokeControllerMethod(Method method, Object[] forceArgs) throws Exception { if (Modifier.isStatic(method.getModifiers()) && !method.getDeclaringClass().getName().matches("^controllers\\..*\\$class$")) { return invoke( method, null, forceArgs == null ? getActionMethodArgs(method, null) : forceArgs); } else if (Modifier.isStatic(method.getModifiers())) { Object[] args = getActionMethodArgs(method, null); args[0] = Http.Request.current().controllerClass.getDeclaredField("MODULE$").get(null); return invoke(method, null, args); } else { Object instance = null; try { instance = method.getDeclaringClass().getDeclaredField("MODULE$").get(null); } catch (Exception e) { Annotation[] annotations = method.getDeclaredAnnotations(); String annotation = Utils.getSimpleNames(annotations); if (!StringUtils.isEmpty(annotation)) { throw new UnexpectedException( "Method public static void " + method.getName() + "() annotated with " + annotation + " in class " + method.getDeclaringClass().getName() + " is not static."); } // TODO: Find a better error report throw new ActionNotFoundException(Http.Request.current().action, e); } return invoke( method, instance, forceArgs == null ? getActionMethodArgs(method, instance) : forceArgs); } }
// Gets baseUrl from current request or application.baseUrl in application.conf protected static String getBaseUrl() { if (Http.Request.current() == null) { // No current request is present - must get baseUrl from config String appBaseUrl = Play.configuration.getProperty("application.baseUrl", "application.baseUrl"); if (appBaseUrl.endsWith("/")) { // remove the trailing slash appBaseUrl = appBaseUrl.substring(0, appBaseUrl.length() - 1); } return appBaseUrl; } else { return Http.Request.current().getBase(); } }
/** * 현재 사용자가 선호하는 언어를 갱신한다. * * <p>쿠키나 Accept-Language HTTP 헤더에 선호하는 언어가 설정되어 있는 경우, 그것을 현재 로그인한 사용자가 선호하는 언어로 설정한다. */ public static void updatePreferredLanguage() { Http.Request request = Http.Context.current().request(); User user = UserApp.currentUser(); if (user.isAnonymous()) { return; } if (request.acceptLanguages().isEmpty() && request.cookie(Play.langCookieName()) == null) { return; } String code = StringUtils.left(Http.Context.current().lang().code(), 255); if (!code.equals(user.lang)) { user.lang = code; user.update(); } }
public void absolute() { boolean isSecure = Http.Request.current() == null ? false : Http.Request.current().secure; String base = getBaseUrl(); String hostPart = host; String domain = Http.Request.current() == null ? "" : Http.Request.current().get().domain; int port = Http.Request.current() == null ? 80 : Http.Request.current().get().port; if (port != 80 && port != 443) { hostPart += ":" + port; } // ~ if (!url.startsWith("http")) { if (StringUtils.isEmpty(host)) { url = base + url; } else if (host.contains("{_}")) { java.util.regex.Matcher matcher = java.util.regex.Pattern.compile("([-_a-z0-9A-Z]+([.][-_a-z0-9A-Z]+)?)$") .matcher(domain); if (matcher.find()) { url = (isSecure ? "https://" : "http://") + hostPart.replace("{_}", matcher.group(1)) + url; } else { url = (isSecure ? "https://" : "http://") + hostPart + url; } } else { url = (isSecure ? "https://" : "http://") + hostPart + url; } if (method.equals("WS")) { url = url.replaceFirst("https?", "ws"); } } }
public static String reverse(VirtualFile file, boolean absolute) { if (file == null || !file.exists()) { throw new NoRouteFoundException("File not found (" + file + ")"); } String path = file.relativePath(); path = path.substring(path.indexOf("}") + 1); for (Route route : routes) { String staticDir = route.staticDir; if (staticDir != null) { if (!staticDir.startsWith("/")) { staticDir = "/" + staticDir; } if (!staticDir.equals("/") && !staticDir.endsWith("/")) { staticDir = staticDir + "/"; } if (path.startsWith(staticDir)) { String to = route.path + path.substring(staticDir.length()); if (to.endsWith("/index.html")) { to = to.substring(0, to.length() - "/index.html".length() + 1); } if (absolute) { boolean isSecure = Http.Request.current() == null ? false : Http.Request.current().secure; String base = getBaseUrl(); if (!StringUtils.isEmpty(route.host)) { // Compute the host int port = Http.Request.current() == null ? 80 : Http.Request.current().get().port; String host = (port != 80 && port != 443) ? route.host + ":" + port : route.host; to = (isSecure ? "https://" : "http://") + host + to; } else { to = base + to; } } return to; } } } throw new NoRouteFoundException(file.relativePath()); }
@SuppressWarnings("unchecked") public static void resolve(Http.Request request, Http.Response response) { if (!Play.started) { return; } Http.Request.current.set(request); Http.Response.current.set(response); Scope.Params.current.set(request.params); Scope.RenderArgs.current.set(new Scope.RenderArgs()); Scope.RouteArgs.current.set(new Scope.RouteArgs()); Scope.Session.current.set(Scope.Session.restore()); Scope.Flash.current.set(Scope.Flash.restore()); CachedBoundActionMethodArgs.init(); ControllersEnhancer.currentAction.set(new Stack<String>()); if (request.resolved) { return; } // Route and resolve format if not already done if (request.action == null) { Play.pluginCollection.routeRequest(request); Route route = Router.route(request); Play.pluginCollection.onRequestRouting(route); } request.resolveFormat(); // Find the action method try { Method actionMethod = null; Object[] ca = getActionMethod(request.action); actionMethod = (Method) ca[1]; request.controller = ((Class) ca[0]).getName().substring(12).replace("$", ""); request.controllerClass = ((Class) ca[0]); request.actionMethod = actionMethod.getName(); request.action = request.controller + "." + request.actionMethod; request.invokedMethod = actionMethod; if (Logger.isTraceEnabled()) { Logger.trace("------- %s", actionMethod); } request.resolved = true; } catch (ActionNotFoundException e) { Logger.error(e, "%s action not found", e.getAction()); throw new NotFound(String.format("%s action not found", e.getAction())); } }
public static Route route(Http.Request request) { if (Logger.isTraceEnabled()) { Logger.trace("Route: " + request.path + " - " + request.querystring); } // request method may be overriden if a x-http-method-override parameter is given if (request.querystring != null && methodOverride.matches(request.querystring)) { Matcher matcher = methodOverride.matcher(request.querystring); if (matcher.matches()) { if (Logger.isTraceEnabled()) { Logger.trace( "request method %s overriden to %s ", request.method, matcher.group("method")); } request.method = matcher.group("method"); } } for (Route route : routes) { Map<String, String> args = route.matches(request.method, request.path, request.format, request.domain); if (args != null) { request.routeArgs = args; request.action = route.action; if (args.containsKey("format")) { request.format = args.get("format"); } if (request.action.indexOf("{") > -1) { // more optimization ? for (String arg : request.routeArgs.keySet()) { request.action = request.action.replace("{" + arg + "}", request.routeArgs.get(arg)); } } if (request.action.equals("404")) { throw new NotFound(route.path); } return route; } } // Not found - if the request was a HEAD, let's see if we can find a corresponding GET if (request.method.equalsIgnoreCase("head")) { request.method = "GET"; Route route = route(request); request.method = "HEAD"; if (route != null) { return route; } } throw new NotFound(request.method, request.path); }
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); }
static Object invokeWithContinuation(Method method, Object instance, Object[] realArgs) throws Exception { // Callback case if (Http.Request.current().args.containsKey(A)) { // Action0 instance = Http.Request.current().args.get(A); Future f = (Future) Http.Request.current().args.get(F); Scope.RenderArgs renderArgs = (Scope.RenderArgs) Request.current().args.remove(ActionInvoker.CONTINUATIONS_STORE_RENDER_ARGS); Scope.RenderArgs.current.set(renderArgs); if (f == null) { method = instance.getClass().getDeclaredMethod("invoke"); method.setAccessible(true); return method.invoke(instance); } else { method = instance.getClass().getDeclaredMethod("invoke", Object.class); method.setAccessible(true); return method.invoke(instance, f.get()); } } // Continuations case Continuation continuation = (Continuation) Http.Request.current().args.get(C); if (continuation == null) { continuation = new Continuation(new StackRecorder((Runnable) null)); } StackRecorder pStackRecorder = new StackRecorder(continuation.stackRecorder); Object result = null; final StackRecorder old = pStackRecorder.registerThread(); try { pStackRecorder.isRestoring = !pStackRecorder.isEmpty(); // Execute code result = method.invoke(instance, realArgs); if (pStackRecorder.isCapturing) { if (pStackRecorder.isEmpty()) { throw new IllegalStateException( "stack corruption. Is " + method + " instrumented for javaflow?"); } Object trigger = pStackRecorder.value; Continuation nextContinuation = new Continuation(pStackRecorder); Http.Request.current().args.put(C, nextContinuation); if (trigger instanceof Long) { throw new Suspend((Long) trigger); } if (trigger instanceof Integer) { throw new Suspend(((Integer) trigger).longValue()); } if (trigger instanceof Future) { throw new Suspend((Future) trigger); } throw new UnexpectedException("Unexpected continuation trigger -> " + trigger); } else { Http.Request.current().args.remove(C); } } finally { pStackRecorder.deregisterThread(old); } return result; }
/** * Checks and calla all methods in controller annotated with @Finally. The caughtException-value * is sent as argument to @Finally-method if method has one argument which is Throwable * * @param request * @param caughtException If @Finally-methods are called after an error, this variable holds the * caught error * @throws PlayException */ static void handleFinallies(Http.Request request, Throwable caughtException) throws PlayException { if (Controller.getControllerClass() == null) { // skip it return; } try { List<Method> allFinally = Java.findAllAnnotatedMethods(Controller.getControllerClass(), Finally.class); Collections.sort( allFinally, new Comparator<Method>() { public int compare(Method m1, Method m2) { Finally finally1 = m1.getAnnotation(Finally.class); Finally finally2 = m2.getAnnotation(Finally.class); return finally1.priority() - finally2.priority(); } }); ControllerInstrumentation.stopActionCall(); for (Method aFinally : allFinally) { String[] unless = aFinally.getAnnotation(Finally.class).unless(); String[] only = aFinally.getAnnotation(Finally.class).only(); boolean skip = false; for (String un : only) { if (!un.contains(".")) { un = aFinally.getDeclaringClass().getName().substring(12) + "." + un; } if (un.equals(request.action)) { skip = false; break; } else { skip = true; } } for (String un : unless) { if (!un.contains(".")) { un = aFinally.getDeclaringClass().getName().substring(12) + "." + un; } if (un.equals(request.action)) { skip = true; break; } } if (!skip) { aFinally.setAccessible(true); // check if method accepts Throwable as only parameter Class[] parameterTypes = aFinally.getParameterTypes(); if (parameterTypes.length == 1 && parameterTypes[0] == Throwable.class) { // invoking @Finally method with caughtException as parameter invokeControllerMethod(aFinally, new Object[] {caughtException}); } else { // invoce @Finally-method the regular way without caughtException invokeControllerMethod(aFinally, null); } } } } catch (InvocationTargetException ex) { StackTraceElement element = PlayException.getInterestingStrackTraceElement(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 (Exception e) { throw new UnexpectedException("Exception while doing @Finally", e); } }
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) { Controller.class.getDeclaredField("params").set(null, Scope.Params.current()); Controller.class.getDeclaredField("request").set(null, Http.Request.current()); Controller.class.getDeclaredField("response").set(null, Http.Response.current()); Controller.class.getDeclaredField("session").set(null, Scope.Session.current()); Controller.class.getDeclaredField("flash").set(null, Scope.Flash.current()); Controller.class.getDeclaredField("renderArgs").set(null, Scope.RenderArgs.current()); Controller.class.getDeclaredField("routeArgs").set(null, Scope.RouteArgs.current()); Controller.class.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 (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); Collections.sort( catches, new Comparator<Method>() { public int compare(Method m1, Method m2) { Catch catch1 = m1.getAnnotation(Catch.class); Catch catch2 = m2.getAnnotation(Catch.class); return catch1.priority() - catch2.priority(); } }); 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.getInterestingStrackTraceElement(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 { if (monitor != null) { monitor.stop(); } } }