diff --git a/framework/build.xml b/framework/build.xml index 1d917b0fa8..0a5750d240 100644 --- a/framework/build.xml +++ b/framework/build.xml @@ -94,12 +94,13 @@ Play! ${version}]]> Guillaume Bort & zenexity - Distributed under Apache 2 licence, without any warrantly]]> - + + - + - + diff --git a/framework/src/play/CorePlugin.java b/framework/src/play/CorePlugin.java index d09a92733c..ac797bfb2e 100644 --- a/framework/src/play/CorePlugin.java +++ b/framework/src/play/CorePlugin.java @@ -42,6 +42,10 @@ public class CorePlugin extends PlayPlugin { /** * Get the application status + * + * @param json + * true if the status should be return in JSON + * @return application status */ public static String computeApplicationStatus(boolean json) { if (json) { diff --git a/framework/src/play/Invoker.java b/framework/src/play/Invoker.java index 9564074c3f..1531eae74b 100644 --- a/framework/src/play/Invoker.java +++ b/framework/src/play/Invoker.java @@ -13,6 +13,9 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; +import com.jamonapi.Monitor; +import com.jamonapi.MonitorFactory; + import play.Play.Mode; import play.classloading.ApplicationClassloader; import play.classloading.enhancers.LocalvariablesNamesEnhancer.LocalVariablesNamesTracer; @@ -23,9 +26,6 @@ import play.libs.F.Promise; import play.utils.PThreadFactory; -import com.jamonapi.Monitor; -import com.jamonapi.MonitorFactory; - /** * Run some code in a Play! context */ @@ -38,7 +38,9 @@ public class Invoker { /** * Run the code in a new thread took from a thread pool. - * @param invocation The code to run + * + * @param invocation + * The code to run * @return The future object, to know when the task is completed */ public static Future invoke(Invocation invocation) { @@ -50,8 +52,11 @@ public static Future invoke(Invocation invocation) { /** * Run the code in a new thread after a delay - * @param invocation The code to run - * @param millis The time to wait before, in milliseconds + * + * @param invocation + * The code to run + * @param millis + * The time to wait before, in milliseconds * @return The future object, to know when the task is completed */ public static Future invoke(Invocation invocation, long millis) { @@ -62,7 +67,9 @@ public static Future invoke(Invocation invocation, long millis) { /** * Run the code in the same thread than caller. - * @param invocation The code to run + * + * @param invocation + * The code to run */ public static void invokeInThread(DirectInvocation invocation) { boolean retry = true; @@ -154,8 +161,10 @@ public boolean isAnnotationPresent(Class clazz) { } /** - * Returns the InvocationType for this invocation - Ie: A plugin can use this to - * find out if it runs in the context of a background Job + * Returns the InvocationType for this invocation - Ie: A plugin can use this to find out if it runs in the + * context of a background Job + * + * @return the InvocationType for this invocation */ public String getInvocationType() { return invocationType; @@ -186,15 +195,15 @@ public abstract static class Invocation implements Runnable { /** * Override this method + * * @throws java.lang.Exception + * Thrown if Invocation encounters any problems */ public abstract void execute() throws Exception; - /** - * Needs this method to do stuff *before* init() is executed. - * The different Invocation-implementations does a lot of stuff in init() - * and they might do it before calling super.init() + * Needs this method to do stuff *before* init() is executed. The different Invocation-implementations does a + * lot of stuff in init() and they might do it before calling super.init() */ protected void preInit() { // clear language for this request - we're resolving it later when it is needed @@ -203,6 +212,8 @@ protected void preInit() { /** * Init the call (especially useful in DEV mode to detect changes) + * + * @return true if successful */ public boolean init() { Thread.currentThread().setContextClassLoader(Play.classloader); @@ -217,7 +228,6 @@ public boolean init() { return true; } - public abstract InvocationContext getInvocationContext(); /** @@ -229,8 +239,7 @@ public void before() { } /** - * Things to do after an Invocation. - * (if the Invocation code has not thrown any exception) + * Things to do after an Invocation. (if the Invocation code has not thrown any exception) */ public void after() { Play.pluginCollection.afterInvocation(); @@ -239,6 +248,9 @@ public void after() { /** * Things to do when the whole invocation has succeeded (before + execute + after) + * + * @throws java.lang.Exception + * Thrown if Invoker encounters any problems */ public void onSuccess() throws Exception { Play.pluginCollection.onInvocationSuccess(); @@ -246,6 +258,9 @@ public void onSuccess() throws Exception { /** * Things to do if the Invocation code thrown an exception + * + * @param e + * The exception */ public void onException(Throwable e) { Play.pluginCollection.onInvocationException(e); @@ -257,7 +272,9 @@ public void onException(Throwable e) { /** * The request is suspended + * * @param suspendRequest + * the suspended request */ public void suspend(Suspend suspendRequest) { if (suspendRequest.task != null) { @@ -276,10 +293,10 @@ public void _finally() { } private void withinFilter(play.libs.F.Function0 fct) throws Throwable { - F.Option> filters = Play.pluginCollection.composeFilters(); - if (filters.isDefined()) { - filters.get().withinFilter(fct); - } + F.Option> filters = Play.pluginCollection.composeFilters(); + if (filters.isDefined()) { + filters.get().withinFilter(fct); + } } /** @@ -351,7 +368,8 @@ public InvocationContext getInvocationContext() { * Init executor at load time. */ static { - int core = Integer.parseInt(Play.configuration.getProperty("play.pool", Play.mode == Mode.DEV ? "1" : ((Runtime.getRuntime().availableProcessors() + 1) + ""))); + int core = Integer.parseInt(Play.configuration.getProperty("play.pool", + Play.mode == Mode.DEV ? "1" : ((Runtime.getRuntime().availableProcessors() + 1) + ""))); executor = new ScheduledThreadPoolExecutor(core, new PThreadFactory("play"), new ThreadPoolExecutor.AbortPolicy()); } @@ -364,7 +382,7 @@ public static class Suspend extends PlayException { * Suspend for a timeout (in milliseconds). */ long timeout; - + /** * Wait for task execution. */ diff --git a/framework/src/play/Play.java b/framework/src/play/Play.java index 361f14081c..2f2318ec37 100644 --- a/framework/src/play/Play.java +++ b/framework/src/play/Play.java @@ -1,13 +1,23 @@ package play; +import java.io.BufferedReader; import java.io.File; +import java.io.IOException; import java.io.InputStreamReader; -import java.io.BufferedReader; import java.io.LineNumberReader; -import java.io.IOException; import java.net.URI; import java.net.URL; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.Set; import java.util.concurrent.CopyOnWriteArrayList; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -54,6 +64,7 @@ public boolean isProd() { return this == PROD; } } + /** * Is the application initialized */ @@ -144,10 +155,8 @@ public boolean isProd() { */ public static PluginCollection pluginCollection = new PluginCollection(); /** - * Readonly list containing currently enabled plugins. - * This list is updated from pluginCollection when pluginCollection is modified - * Play plugins - * Use pluginCollection instead. + * Readonly list containing currently enabled plugins. This list is updated from pluginCollection when + * pluginCollection is modified Play plugins Use pluginCollection instead. */ @Deprecated public static List plugins = pluginCollection.getEnabledPlugins(); @@ -177,16 +186,17 @@ public boolean isProd() { public static String defaultWebEncoding = "utf-8"; /** - * This flag indicates if the app is running in a standalone Play server or - * as a WAR in an applicationServer + * This flag indicates if the app is running in a standalone Play server or as a WAR in an applicationServer */ public static boolean standalonePlayServer = true; /** * Init the framework * - * @param root The application path - * @param id The framework id to use + * @param root + * The application path + * @param id + * The framework id to use */ public static void init(File root, String id) { // Simple things @@ -208,8 +218,8 @@ public static void init(File root, String id) { Logger.init(); String logLevel = configuration.getProperty("application.log", "INFO"); - //only override log-level if Logger was not configured manually - if( !Logger.configuredManually) { + // only override log-level if Logger was not configured manually + if (!Logger.configuredManually) { Logger.setUp(logLevel); } Logger.recordCaller = Boolean.parseBoolean(configuration.getProperty("application.log.recordCaller", "false")); @@ -249,7 +259,7 @@ public static void init(File root, String id) { Logger.error("Illegal mode '%s', use either prod or dev", configuration.getProperty("application.mode")); fatalServerErrorOccurred(); } - + // Force the Production mode if forceProd or precompile is activate // Set to the Prod mode must be done before loadModules call // as some modules (e.g. DocViewer) is only available in DEV @@ -264,7 +274,7 @@ public static void init(File root, String id) { VirtualFile appRoot = VirtualFile.open(applicationPath); roots.clear(); roots.add(appRoot); - + javaPath.clear(); javaPath.add(appRoot.child("app")); javaPath.add(appRoot.child("conf")); @@ -274,7 +284,7 @@ public static void init(File root, String id) { if (appRoot.child("app/views").exists() || (usePrecompiled && appRoot.child("precompiled/templates/app/views").exists())) { templatesPath.add(appRoot.child("app/views")); } - + // Main route file routes = appRoot.child("conf/routes"); @@ -297,7 +307,7 @@ public static void init(File root, String id) { // Default cookie domain Http.Cookie.defaultDomain = configuration.getProperty("application.defaultCookieDomain", null); - if (Http.Cookie.defaultDomain!=null) { + if (Http.Cookie.defaultDomain != null) { Logger.info("Using default cookie domain: " + Http.Cookie.defaultDomain); } @@ -337,7 +347,8 @@ public static void guessFrameworkPath() { } else if (uri.getScheme().equals("file")) { frameworkPath = new File(uri).getParentFile().getParentFile().getParentFile().getParentFile(); } else { - throw new UnexpectedException("Cannot find the Play! framework - trying with uri: " + uri + " scheme " + uri.getScheme()); + throw new UnexpectedException( + "Cannot find the Play! framework - trying with uri: " + uri + " scheme " + uri.getScheme()); } } } catch (Exception e) { @@ -354,7 +365,7 @@ public static void readConfiguration() { extractHttpPort(); // Plugins pluginCollection.onConfigurationRead(); - } + } private static void extractHttpPort() { String javaCommand = System.getProperty("sun.java.command", ""); @@ -364,27 +375,26 @@ private static void extractHttpPort() { } } - private static Properties readOneConfigurationFile(String filename) { - Properties propsFromFile=null; + Properties propsFromFile = null; VirtualFile appRoot = VirtualFile.open(applicationPath); - + VirtualFile conf = appRoot.child("conf/" + filename); if (confs.contains(conf)) { throw new RuntimeException("Detected recursive @include usage. Have seen the file " + filename + " before"); } - + try { propsFromFile = IO.readUtf8Properties(conf.inputstream()); } catch (RuntimeException e) { if (e.getCause() instanceof IOException) { - Logger.fatal("Cannot read "+filename); + Logger.fatal("Cannot read " + filename); fatalServerErrorOccurred(); } } confs.add(conf); - + // OK, check for instance specifics configuration Properties newConfiguration = new OrderSafeProperties(); Pattern pattern = Pattern.compile("^%([a-zA-Z0-9_\\-]+)\\.(.*)$"); @@ -438,7 +448,7 @@ private static Properties readOneConfigurationFile(String filename) { if (key.toString().startsWith("@include.")) { try { String filenameToInclude = propsFromFile.getProperty(key.toString()); - toInclude.putAll( readOneConfigurationFile(filenameToInclude) ); + toInclude.putAll(readOneConfigurationFile(filenameToInclude)); } catch (Exception ex) { Logger.warn(ex, "Missing include: %s", key); } @@ -450,8 +460,7 @@ private static Properties readOneConfigurationFile(String filename) { } /** - * Start the application. - * Recall to restart ! + * Start the application. Recall to restart ! */ public static synchronized void start() { try { @@ -460,11 +469,11 @@ public static synchronized void start() { stop(); } - if( standalonePlayServer) { + if (standalonePlayServer) { // Can only register shutdown-hook if running as standalone server if (!shutdownHookEnabled) { - //registers shutdown hook - Now there's a good chance that we can notify - //our plugins that we're going down when some calls ctrl+c or just kills our process.. + // registers shutdown hook - Now there's a good chance that we can notify + // our plugins that we're going down when some calls ctrl+c or just kills our process.. shutdownHookEnabled = true; Thread hook = new Thread() { @Override @@ -492,8 +501,8 @@ public void run() { // Configure logs String logLevel = configuration.getProperty("application.log", "INFO"); - //only override log-level if Logger was not configured manually - if( !Logger.configuredManually) { + // only override log-level if Logger was not configured manually + if (!Logger.configuredManually) { Logger.setUp(logLevel); } Logger.recordCaller = Boolean.parseBoolean(configuration.getProperty("application.log.recordCaller", "false")); @@ -515,18 +524,17 @@ public void run() { // Default web encoding String _defaultWebEncoding = configuration.getProperty("application.web_encoding"); - if( _defaultWebEncoding != null ) { + if (_defaultWebEncoding != null) { Logger.info("Using custom default web encoding: " + _defaultWebEncoding); defaultWebEncoding = _defaultWebEncoding; // Must update current response also, since the request/response triggering // this configuration-loading in dev-mode have already been // set up with the previous encoding - if( Http.Response.current() != null ) { + if (Http.Response.current() != null) { Http.Response.current().encoding = _defaultWebEncoding; } } - // Try to load all classes Play.classloader.getAllClasses(); @@ -563,11 +571,17 @@ public void run() { } catch (PlayException e) { started = false; - try { Cache.stop(); } catch (Exception ignored) {} + try { + Cache.stop(); + } catch (Exception ignored) { + } throw e; } catch (Exception e) { started = false; - try { Cache.stop(); } catch (Exception ignored) {} + try { + Cache.stop(); + } catch (Exception ignored) { + } throw new UnexpectedException(e); } } @@ -637,7 +651,7 @@ public static synchronized void detectChanges() { } try { pluginCollection.beforeDetectingChanges(); - if(!pluginCollection.detectClassesChange()) { + if (!pluginCollection.detectClassesChange()) { classloader.detectChanges(); } Router.detectChanges(ctxPath); @@ -651,8 +665,7 @@ public static synchronized void detectChanges() { if (started) { if (e.getCause() != null && e.getCause() != e) { Logger.info("Restart: " + e.getMessage() + ", caused by: " + e.getCause()); - } - else { + } else { Logger.info("Restart: " + e.getMessage()); } } @@ -665,11 +678,9 @@ public static synchronized void detectChanges() { @SuppressWarnings("unchecked") public static T plugin(Class clazz) { - return (T)pluginCollection.getPluginInstance((Class)clazz); + return (T) pluginCollection.getPluginInstance((Class) clazz); } - - /** * Allow some code to run very early in Play - Use with caution ! */ @@ -699,17 +710,17 @@ public static void initStaticStuff() { } /** - * Load all modules. You can even specify the list using the MODULES - * environment variable. + * Load all modules. You can even specify the list using the MODULES environment variable. */ public static void loadModules() { loadModules(VirtualFile.open(applicationPath)); } /** - * Load all modules. - * You can even specify the list using the MODULES environment variable. - * @param appRoot : the application path virtual file + * Load all modules. You can even specify the list using the MODULES environment variable. + * + * @param appRoot + * the application path virtual file */ public static void loadModules(VirtualFile appRoot) { if (System.getenv("MODULES") != null) { @@ -718,12 +729,12 @@ public static void loadModules(VirtualFile appRoot) { for (String m : System.getenv("MODULES").split(System.getProperty("os.name").startsWith("Windows") ? ";" : ":")) { File modulePath = new File(m); if (!modulePath.exists() || !modulePath.isDirectory()) { - Logger.error("Module %s will not be loaded because %s does not exist", modulePath.getName(), modulePath.getAbsolutePath()); + Logger.error("Module %s will not be loaded because %s does not exist", modulePath.getName(), + modulePath.getAbsolutePath()); } else { String modulePathName = modulePath.getName(); - String moduleName = modulePathName.contains("-") ? - modulePathName.substring(0, modulePathName.lastIndexOf("-")) : - modulePathName; + String moduleName = modulePathName.contains("-") ? modulePathName.substring(0, modulePathName.lastIndexOf("-")) + : modulePathName; addModule(appRoot, moduleName, modulePath); } } @@ -745,13 +756,14 @@ public static void loadModules(VirtualFile appRoot) { DependenciesManager dm = new DependenciesManager(applicationPath, frameworkPath, userHome); modules = dm.retrieveModules(); } catch (Exception e) { - Logger.error("There was a problem parsing dependencies.yml (module will not be loaded in order of the dependencies.yml)", e); + Logger.error("There was a problem parsing dependencies.yml (module will not be loaded in order of the dependencies.yml)", + e); // Load module without considering the dependencies.yml order modules.addAll(Arrays.asList(localModules.list())); } - for (Iterator iter = modules.iterator(); iter.hasNext(); ) { - String moduleName = (String) iter.next(); + for (Iterator iter = modules.iterator(); iter.hasNext();) { + String moduleName = iter.next(); File module = new File(localModules, moduleName); @@ -784,21 +796,21 @@ public static void loadModules(VirtualFile appRoot) { * Add a play application (as plugin) * * @param name - * : the module name + * the module name * @param path * The application path */ public static void addModule(String name, File path) { addModule(VirtualFile.open(applicationPath), name, path); } - + /** * Add a play application (as plugin) * * @param appRoot - * : the application path virtual file + * the application path virtual file * @param name - * : the module name + * the module name * @param path * The application path */ @@ -808,10 +820,12 @@ public static void addModule(VirtualFile appRoot, String name, File path) { if (root.child("app").exists()) { javaPath.add(root.child("app")); } - if (root.child("app/views").exists() || (usePrecompiled && appRoot.child("precompiled/templates/from_module_" + name + "/app/views").exists())) { + if (root.child("app/views").exists() + || (usePrecompiled && appRoot.child("precompiled/templates/from_module_" + name + "/app/views").exists())) { templatesPath.add(root.child("app/views")); } - if (root.child("conf/routes").exists() || (usePrecompiled && appRoot.child("precompiled/templates/from_module_" + name + "/conf/routes").exists())) { + if (root.child("conf/routes").exists() + || (usePrecompiled && appRoot.child("precompiled/templates/from_module_" + name + "/conf/routes").exists())) { modulesRoutes.put(name, root.child("conf/routes")); } roots.add(root); @@ -823,7 +837,8 @@ public static void addModule(VirtualFile appRoot, String name, File path) { /** * Search a VirtualFile in all loaded applications and plugins * - * @param path Relative path from the applications root + * @param path + * Relative path from the applications root * @return The virtualFile or null */ public static VirtualFile getVirtualFile(String path) { @@ -833,7 +848,8 @@ public static VirtualFile getVirtualFile(String path) { /** * Search a File in the current application * - * @param path Relative path from the application root + * @param path + * Relative path from the application root * @return The file even if it doesn't exist */ public static File getFile(String path) { @@ -841,17 +857,15 @@ public static File getFile(String path) { } /** - * Returns true if application is runing in test-mode. - * Test-mode is resolved from the framework id. + * Returns true if application is runing in test-mode. Test-mode is resolved from the framework id. * - * Your app is running in test-mode if the framwork id (Play.id) - * is 'test' or 'test-?.*' + * Your app is running in test-mode if the framwork id (Play.id) is 'test' or 'test-?.*' + * * @return true if testmode */ - public static boolean runingInTestMode(){ + public static boolean runingInTestMode() { return id.matches("test|test-?.*"); } - /** * Call this method when there has been a fatal error that Play cannot recover from diff --git a/framework/src/play/PlayPlugin.java b/framework/src/play/PlayPlugin.java index e78f53cbd0..9781e4f5ec 100644 --- a/framework/src/play/PlayPlugin.java +++ b/framework/src/play/PlayPlugin.java @@ -1,6 +1,17 @@ package play; +import static java.util.Collections.emptyList; +import static java.util.Collections.emptyMap; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; +import java.lang.reflect.Type; +import java.util.Collection; +import java.util.List; +import java.util.Map; + import com.google.gson.JsonObject; + import play.classloading.ApplicationClasses.ApplicationClass; import play.data.binding.RootParamNode; import play.db.Model; @@ -15,14 +26,6 @@ import play.test.TestEngine.TestResults; import play.vfs.VirtualFile; -import java.lang.annotation.Annotation; -import java.lang.reflect.Method; -import java.lang.reflect.Type; -import java.util.*; - -import static java.util.Collections.emptyList; -import static java.util.Collections.emptyMap; - /** * A framework plugin */ @@ -45,6 +48,10 @@ public boolean compileSources() { /** * Run a test class + * + * @param clazz + * the class to run + * @return : tests results */ public TestResults runTest(Class clazz) { return null; @@ -52,7 +59,20 @@ public TestResults runTest(Class clazz) { /** * Use method using RootParamNode instead - * @return + * + * @param name + * the name of the object + * @param clazz + * the class of the object to bind + * @param type + * type + * @param annotations + * annotation on the object + * @param params + * parameters to bind + * @return binding object + * + * @deprecated use {@link #bind(RootParamNode, String, Class, Type, Annotation[])} */ @Deprecated public Object bind(String name, Class clazz, Type type, Annotation[] annotations, Map params) { @@ -62,16 +82,35 @@ public Object bind(String name, Class clazz, Type type, Annotation[] annotations /** * Called when play need to bind a Java object from HTTP params. * - * When overriding this method, do not call super impl.. super impl is calling old bind method - * to be backward compatible. - */ - public Object bind( RootParamNode rootParamNode, String name, Class clazz, Type type, Annotation[] annotations) { + * When overriding this method, do not call super impl.. super impl is calling old bind method to be backward + * compatible. + * + * @param rootParamNode + * parameters to bind + * @param name + * the name of the object + * @param clazz + * the class of the object to bind + * @param type + * type + * @param annotations + * annotation on the object + * @return binding object + */ + public Object bind(RootParamNode rootParamNode, String name, Class clazz, Type type, Annotation[] annotations) { // call old method to be backward compatible return bind(name, clazz, type, annotations, rootParamNode.originalParams); } /** - * Use bindBean instead + * @deprecated Use bindBean instead + * @param name + * the name of the object + * @param o + * object to bind + * @param params + * parameters to bind + * @return binding object */ @Deprecated public Object bind(String name, Object o, Map params) { @@ -79,23 +118,46 @@ public Object bind(String name, Object o, Map params) { } /** - * Called when play need to bind an existing Java object from HTTP params. - * When overriding this method, DO NOT call the super method, since its default impl is to - * call the old bind method to be backward compatible. + * Called when play need to bind an existing Java object from HTTP params. When overriding this method, DO NOT call + * the super method, since its default impl is to call the old bind method to be backward compatible. + * + * @param rootParamNode + * parameters to bind + * @param name + * the name of the object + * @param bean + * object to bind + * @return binding object */ public Object bindBean(RootParamNode rootParamNode, String name, Object bean) { // call old method to be backward compatible. return bind(name, bean, rootParamNode.originalParams); } + /** + * Unbind an object + * + * @param src + * object to unbind + * @param name + * the name of the object + * @return List of parameters + */ public Map unBind(Object src, String name) { return null; } - + /** - * Translate the given key for the given locale and arguments. - * If null is returned, Play's normal message translation mechanism will be - * used. + * Translate the given key for the given locale and arguments. If null is returned, Play's normal message + * translation mechanism will be used. + * + * @param locale + * the locale we want + * @param key + * the message key + * @param args + * arguments of the messages + * @return the formatted string */ public String getMessage(String locale, Object key, Object... args) { return null; @@ -103,6 +165,8 @@ public String getMessage(String locale, Object key, Object... args) { /** * Return the plugin status + * + * @return the plugin status */ public String getStatus() { return null; @@ -110,6 +174,8 @@ public String getStatus() { /** * Return the plugin status in JSON format + * + * @return the plugin status in JSON format */ public JsonObject getJsonStatus() { return null; @@ -117,15 +183,21 @@ public JsonObject getJsonStatus() { /** * Enhance this class + * * @param applicationClass + * the class to enhance * @throws java.lang.Exception + * if cannot enhance the class */ public void enhance(ApplicationClass applicationClass) throws Exception { } /** * This hook is not plugged, don't implement it + * * @param template + * the template to compile + * @deprecated */ @Deprecated public void onTemplateCompilation(Template template) { @@ -133,9 +205,14 @@ public void onTemplateCompilation(Template template) { /** * Give a chance to this plugin to fully manage this request - * @param request The Play request - * @param response The Play response + * + * @param request + * The Play request + * @param response + * The Play response * @return true if this plugin has managed this request + * @throws java.lang.Exception + * if cannot enhance the class */ public boolean rawInvocation(Request request, Response response) throws Exception { return false; @@ -143,8 +220,13 @@ public boolean rawInvocation(Request request, Response response) throws Exceptio /** * Let a chance to this plugin to manage a static resource - * @param request The Play request - * @param response The Play response + * + * @param file + * The requested file + * @param request + * The Play request + * @param response + * The Play response * @return true if this plugin has managed this request */ public boolean serveStatic(VirtualFile file, Request request, Response response) { @@ -154,28 +236,32 @@ public boolean serveStatic(VirtualFile file, Request request, Response response) public void beforeDetectingChanges() { } + /** + * @param file + * the file of the template to load + * @return the template object + */ public Template loadTemplate(VirtualFile file) { return null; } /** - * It's time for the plugin to detect changes. - * Throw an exception is the application must be reloaded. + * It's time for the plugin to detect changes. Throw an exception is the application must be reloaded. */ public void detectChange() { } /** - * It's time for the plugin to detect changes. - * Throw an exception is the application must be reloaded. + * It's time for the plugin to detect changes. Throw an exception is the application must be reloaded. + * + * @return false si no change detected */ public boolean detectClassesChange() { return false; } /** - * Called at application start (and at each reloading) - * Time to start stateful things. + * Called at application start (and at each reloading) Time to start stateful things. */ public void onApplicationStart() { } @@ -187,52 +273,52 @@ public void afterApplicationStart() { } /** - * Called at application stop (and before each reloading) - * Time to shutdown stateful things. + * Called at application stop (and before each reloading) Time to shutdown stateful things. */ public void onApplicationStop() { } /** - * Called before a Play! invocation. - * Time to prepare request specific things. + * Called before a Play! invocation. Time to prepare request specific things. */ public void beforeInvocation() { } /** - * Called after an invocation. - * (unless an exception has been thrown). - * Time to close request specific things. + * Called after an invocation. (unless an exception has been thrown). Time to close request specific things. */ public void afterInvocation() { } /** * Called if an exception occurred during the invocation. - * @param e The caught exception. + * + * @param e + * The caught exception. */ public void onInvocationException(Throwable e) { } /** - * Called at the end of the invocation. - * (even if an exception occurred). - * Time to close request specific things. + * Called at the end of the invocation. (even if an exception occurred). Time to close request specific things. */ public void invocationFinally() { } /** - * Called before an 'action' invocation, - * ie an HTTP request processing. + * Called before an 'action' invocation, ie an HTTP request processing. + * + * @param actionMethod + * name of the method */ public void beforeActionInvocation(Method actionMethod) { } /** * Called when the action method has thrown a result. - * @param result The result object for the request. + * + * @param result + * The result object for the request. */ public void onActionInvocationResult(Result result) { } @@ -242,7 +328,9 @@ public void onInvocationSuccess() { /** * Called when the request has been routed. - * @param route The route selected. + * + * @param route + * The route selected. */ public void onRequestRouting(Route route) { } @@ -271,25 +359,37 @@ public void onConfigurationRead() { public void onRoutesLoaded() { } - /** + /** * Event may be sent by plugins or other components - * @param message convention: pluginClassShortName.message - * @param context depends on the plugin + * + * @param message + * convention: pluginClassShortName.message + * @param context + * depends on the plugin */ public void onEvent(String message, Object context) { } + /** + * @param modified + * list of modified class + * @return List of class + */ public List onClassesChange(List modified) { return emptyList(); } + /** + * @return List of the template extension + */ public List addTemplateExtensions() { return emptyList(); } /** - * Override to provide additional mime types from your plugin. These mimetypes get priority over - * the default framework mimetypes but not over the application's configuration. + * Override to provide additional mime types from your plugin. These mimetypes get priority over the default + * framework mimetypes but not over the application's configuration. + * * @return a Map from extensions (without dot) to mimetypes */ public Map addMimeTypes() { @@ -297,8 +397,11 @@ public Map addMimeTypes() { } /** - * Let a chance to the plugin to compile it owns classes. - * Must be added to the mutable list. + * Let a chance to the plugin to compile it owns classes. Must be added to the mutable list. + * + * @param classes + * list of class to compile + * @deprecated */ @Deprecated public void compileAll(List classes) { @@ -306,11 +409,18 @@ public void compileAll(List classes) { /** * Let some plugins route themself + * * @param request + * the current request */ public void routeRequest(Request request) { } + /** + * @param modelClass + * class of the model + * @return the Model factory + */ public Model.Factory modelFactory(Class modelClass) { return null; } @@ -320,6 +430,11 @@ public void afterFixtureLoad() { /** * Inter-plugin communication. + * + * @param message + * the message to post + * @param context + * an object */ public static void postEvent(String message, Object context) { Play.pluginCollection.onEvent(message, context); @@ -362,14 +477,14 @@ public Object willBeValidated(Object value) { } /** - * Implement to add some classes that should be considered unit tests but do not extend - * {@link org.junit.Assert} to tests that can be executed by test runner (will be visible in test UI). + * Implement to add some classes that should be considered unit tests but do not extend {@link org.junit.Assert} to + * tests that can be executed by test runner (will be visible in test UI). *

* Note:You probably will also need to override {@link PlayPlugin#runTest(java.lang.Class)} method * to handle unsupported tests execution properly. *

- * Keep in mind that this method can only add tests to currently loaded ones. - * You cannot disable tests this way. You should also make sure you do not duplicate already loaded tests. + * Keep in mind that this method can only add tests to currently loaded ones. You cannot disable tests this way. You + * should also make sure you do not duplicate already loaded tests. * * @return list of plugin supported unit test classes (empty list in default implementation) */ @@ -384,8 +499,8 @@ public Collection getUnitTests() { * Note:You probably will also need to override {@link PlayPlugin#runTest(java.lang.Class)} method * to handle unsupported tests execution properly. *

- * Keep in mind that this method can only add tests to currently loaded ones. - * You cannot disable tests this way. You should also make sure you do not duplicate already loaded tests. + * Keep in mind that this method can only add tests to currently loaded ones. You cannot disable tests this way. You + * should also make sure you do not duplicate already loaded tests. * * @return list of plugin supported functional test classes (empty list in default implementation) */ @@ -393,78 +508,82 @@ public Collection getFunctionalTests() { return emptyList(); } - /** - * Class that define a filter. A filter is a class that wrap a certain behavior around an action. - * You can access your Request and Response object within the filter. See the JPA plugin for an example. - * The JPA plugin wraps a transaction around an action. The filter applies a transaction to the current Action. + /** + * Class that define a filter. A filter is a class that wrap a certain behavior around an action. You can access + * your Request and Response object within the filter. See the JPA plugin for an example. The JPA plugin wraps a + * transaction around an action. The filter applies a transaction to the current Action. */ - public abstract static class Filter - { + public abstract static class Filter { String name; public Filter(String name) { this.name = name; } - + public abstract T withinFilter(play.libs.F.Function0 fct) throws Throwable; /** - * Surround innerFilter with this. (innerFilter after this) - * @param innerFilter filter to be wrapped. - * @return a new Filter object. newFilter.withinFilter(x) is outerFilter.withinFilter(innerFilter.withinFilter(x)) + * Surround innerFilter with this. (innerFilter after this) + * + * @param innerFilter + * filter to be wrapped. + * @return a new Filter object. newFilter.withinFilter(x) is + * outerFilter.withinFilter(innerFilter.withinFilter(x)) */ public Filter decorate(final Filter innerFilter) { - final Filter outerFilter = this; - return new Filter(this.name) { - @Override - public T withinFilter(F.Function0 fct) throws Throwable { - return compose(outerFilter.asFunction(), innerFilter.asFunction()).apply(fct); - } - }; + final Filter outerFilter = this; + return new Filter(this.name) { + @Override + public T withinFilter(F.Function0 fct) throws Throwable { + return compose(outerFilter.asFunction(), innerFilter.asFunction()).apply(fct); + } + }; } /** * Compose two second order functions whose input is a zero param function that returns type T... - * @param outer Function that will wrap inner -- ("outer after inner") - * @param inner Function to be wrapped by outer function -- ("outer after inner") - * @return A function that computes outer(inner(x)) on application. + * + * @param outer + * Function that will wrap inner -- ("outer after inner") + * @param inner + * Function to be wrapped by outer function -- ("outer after inner") + * @return A function that computes outer(inner(x)) on application. */ - private static Function1, T> compose(final Function1, T> outer, final Function1, T> inner) { - - return - new Function1, T>() { - @Override - public T apply(final F.Function0 arg) throws Throwable { - return outer.apply(new F.Function0() { - @Override - public T apply() throws Throwable { - return inner.apply(arg); - } - }); - } - }; + private static Function1, T> compose(final Function1, T> outer, + final Function1, T> inner) { + + return new Function1, T>() { + @Override + public T apply(final F.Function0 arg) throws Throwable { + return outer.apply(new F.Function0() { + @Override + public T apply() throws Throwable { + return inner.apply(arg); + } + }); + } + }; } - private final Function1, T> _asFunction = new Function1, T>() { - @Override - public T apply(F.Function0 arg) throws Throwable { - return withinFilter(arg); - } + @Override + public T apply(F.Function0 arg) throws Throwable { + return withinFilter(arg); + } }; public Function1, T> asFunction() { - return _asFunction; + return _asFunction; } public String getName() { return name; } - //I don't want to add any additional dependencies to the project or use JDK 8 features - //so I'm just rolling my own 1 arg function interface... there must be a better way to do this... + // I don't want to add any additional dependencies to the project or use JDK 8 features + // so I'm just rolling my own 1 arg function interface... there must be a better way to do this... public static interface Function1 { - public O apply(I arg) throws Throwable; + public O apply(I arg) throws Throwable; } } @@ -473,11 +592,12 @@ public final boolean hasFilter() { } /** - * Return the filter implementation for this plugin. - */ + * Return the filter implementation for this plugin. + * + * @return filter object of this plugin + */ public Filter getFilter() { return null; } - } diff --git a/framework/src/play/classloading/ApplicationClasses.java b/framework/src/play/classloading/ApplicationClasses.java index cc3cd9b03b..966961243a 100644 --- a/framework/src/play/classloading/ApplicationClasses.java +++ b/framework/src/play/classloading/ApplicationClasses.java @@ -123,6 +123,9 @@ public List all() { /** * Put a new class to the cache. + * + * @param applicationClass + * The class to add */ public void add(ApplicationClass applicationClass) { classes.put(applicationClass.name, applicationClass); @@ -130,11 +133,20 @@ public void add(ApplicationClass applicationClass) { /** * Remove a class from cache + * + * @param applicationClass + * The class to remove */ public void remove(ApplicationClass applicationClass) { classes.remove(applicationClass.name); } + /** + * Remove a class from cache + * + * @param applicationClass + * The class name to remove + */ public void remove(String applicationClass) { classes.remove(applicationClass); } @@ -144,6 +156,7 @@ public void remove(String applicationClass) { * * @param name * The fully qualified class name + * @return true if the class is loaded */ public boolean hasClass(String name) { return classes.containsKey(name); diff --git a/framework/src/play/classloading/ApplicationClassloader.java b/framework/src/play/classloading/ApplicationClassloader.java index 6e2657a965..f9f686ba66 100644 --- a/framework/src/play/classloading/ApplicationClassloader.java +++ b/framework/src/play/classloading/ApplicationClassloader.java @@ -1,17 +1,8 @@ package play.classloading; -import org.apache.commons.io.IOUtils; -import org.apache.commons.lang.StringUtils; - -import play.Logger; -import play.Play; -import play.cache.Cache; -import play.classloading.ApplicationClasses.ApplicationClass; -import play.classloading.hash.ClassStateHashCreator; -import play.exceptions.RestartNeededException; -import play.exceptions.UnexpectedException; -import play.libs.IO; -import play.vfs.VirtualFile; +import static java.util.Collections.unmodifiableList; +import static java.util.Collections.unmodifiableMap; +import static org.apache.commons.io.IOUtils.closeQuietly; import java.io.File; import java.io.IOException; @@ -25,24 +16,40 @@ import java.security.Permissions; import java.security.ProtectionDomain; import java.security.cert.Certificate; -import java.util.*; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; -import static java.util.Collections.unmodifiableList; -import static java.util.Collections.unmodifiableMap; -import static org.apache.commons.io.IOUtils.closeQuietly; +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang.StringUtils; + +import play.Logger; +import play.Play; +import play.cache.Cache; +import play.classloading.ApplicationClasses.ApplicationClass; +import play.classloading.hash.ClassStateHashCreator; +import play.exceptions.RestartNeededException; +import play.exceptions.UnexpectedException; +import play.libs.IO; +import play.vfs.VirtualFile; /** - * The application classLoader. - * Load the classes from the application Java sources files. + * The application classLoader. Load the classes from the application Java sources files. */ public class ApplicationClassloader extends ClassLoader { - private final ClassStateHashCreator classStateHashCreator = new ClassStateHashCreator(); /** - * A representation of the current state of the ApplicationClassloader. - * It gets a new value each time the state of the classloader changes. + * A representation of the current state of the ApplicationClassloader. It gets a new value each time the state of + * the classloader changes. */ public ApplicationClassloaderState currentState = new ApplicationClassloaderState(); @@ -51,7 +58,7 @@ public class ApplicationClassloader extends ClassLoader { */ public ProtectionDomain protectionDomain; - private final Object lock = new Object(); + private final Object lock = new Object(); public ApplicationClassloader() { super(ApplicationClassloader.class.getClassLoader()); @@ -78,8 +85,8 @@ protected Class loadClass(String name, boolean resolve) throws ClassNotFoundE return c; } - synchronized( lock ) { - // First check if it's an application Class + synchronized (lock) { + // First check if it's an application Class Class applicationClass = loadApplicationClass(name); if (applicationClass != null) { if (resolve) { @@ -96,7 +103,7 @@ public Class loadApplicationClass(String name) { if (ApplicationClass.isClass(name)) { Class maybeAlreadyLoaded = findLoadedClass(name); - if(maybeAlreadyLoaded != null) { + if (maybeAlreadyLoaded != null) { return maybeAlreadyLoaded; } } @@ -149,7 +156,8 @@ public Class loadApplicationClass(String name) { } if (bc != null) { applicationClass.enhancedByteCode = bc; - applicationClass.javaClass = defineClass(applicationClass.name, applicationClass.enhancedByteCode, 0, applicationClass.enhancedByteCode.length, protectionDomain); + applicationClass.javaClass = defineClass(applicationClass.name, applicationClass.enhancedByteCode, 0, + applicationClass.enhancedByteCode.length, protectionDomain); resolveClass(applicationClass.javaClass); if (!applicationClass.isClass()) { applicationClass.javaPackage = applicationClass.javaClass.getPackage(); @@ -163,7 +171,8 @@ public Class loadApplicationClass(String name) { } if (applicationClass.javaByteCode != null || applicationClass.compile() != null) { applicationClass.enhance(); - applicationClass.javaClass = defineClass(applicationClass.name, applicationClass.enhancedByteCode, 0, applicationClass.enhancedByteCode.length, protectionDomain); + applicationClass.javaClass = defineClass(applicationClass.name, applicationClass.enhancedByteCode, 0, + applicationClass.enhancedByteCode.length, protectionDomain); BytecodeCache.cacheBytecode(applicationClass.enhancedByteCode, name, applicationClass.javaSource); resolveClass(applicationClass.javaClass); if (!applicationClass.isClass()) { @@ -296,6 +305,9 @@ public URL nextElement() { /** * Detect Java changes + * + * @throws play.exceptions.RestartNeededException + * Thrown if the application need to be restarted */ public void detectChanges() throws RestartNeededException { // Now check for file modification @@ -316,7 +328,7 @@ public void detectChanges() throws RestartNeededException { for (ApplicationClass applicationClass : modifiedWithDependencies) { if (applicationClass.compile() == null) { Play.classes.classes.remove(applicationClass.name); - currentState = new ApplicationClassloaderState();//show others that we have changed.. + currentState = new ApplicationClassloaderState();// show others that we have changed.. } else { int sigChecksum = applicationClass.sigChecksum; applicationClass.enhance(); @@ -325,10 +337,10 @@ public void detectChanges() throws RestartNeededException { } BytecodeCache.cacheBytecode(applicationClass.enhancedByteCode, applicationClass.name, applicationClass.javaSource); newDefinitions.add(new ClassDefinition(applicationClass.javaClass, applicationClass.enhancedByteCode)); - currentState = new ApplicationClassloaderState();//show others that we have changed.. + currentState = new ApplicationClassloaderState();// show others that we have changed.. } } - + if (!newDefinitions.isEmpty()) { Cache.clear(); if (HotswapAgent.enabled) { @@ -353,11 +365,11 @@ public void detectChanges() throws RestartNeededException { for (ApplicationClass applicationClass : Play.classes.all()) { if (!applicationClass.javaFile.exists()) { Play.classes.classes.remove(applicationClass.name); - currentState = new ApplicationClassloaderState();//show others that we have changed.. + currentState = new ApplicationClassloaderState();// show others that we have changed.. } if (applicationClass.name.contains("$")) { Play.classes.classes.remove(applicationClass.name); - currentState = new ApplicationClassloaderState();//show others that we have changed.. + currentState = new ApplicationClassloaderState();// show others that we have changed.. // Ok we have to remove all classes from the same file ... VirtualFile vf = applicationClass.javaFile; for (ApplicationClass ac : Play.classes.all()) { @@ -370,7 +382,7 @@ public void detectChanges() throws RestartNeededException { throw new RestartNeededException("Path has changed"); } } - + /** * Used to track change of the application sources path */ @@ -382,6 +394,7 @@ private int computePathHash() { /** * Try to load all .java files found. + * * @return The list of well defined Class */ public List getAllClasses() { @@ -450,13 +463,15 @@ public int compare(Class o1, Class o2) { } return allClasses; } - + private List allClasses; private Map allClassesByNormalizedName; /** * Retrieve all application classes assignable to this class. - * @param clazz The superclass, or the interface. + * + * @param clazz + * The superclass, or the interface. * @return A list of class */ public List getAssignableClasses(Class clazz) { @@ -483,7 +498,9 @@ public List getAssignableClasses(Class clazz) { /** * Find a class in a case insensitive way - * @param name The class name. + * + * @param name + * The class name. * @return a class */ public Class getClassIgnoreCase(String name) { @@ -501,7 +518,9 @@ public Class getClassIgnoreCase(String name) { /** * Retrieve all application classes with a specific annotation. - * @param clazz The annotation class. + * + * @param clazz + * The annotation class. * @return A list of class */ public List getAnnotatedClasses(Class clazz) { @@ -520,7 +539,7 @@ public List getAnnotatedClasses(Class[] clazz) { } return results; } - + private List getAllClasses(VirtualFile path) { return getAllClasses(path, ""); } diff --git a/framework/src/play/classloading/ApplicationCompiler.java b/framework/src/play/classloading/ApplicationCompiler.java index 48acb3c7e8..5b0e608f30 100644 --- a/framework/src/play/classloading/ApplicationCompiler.java +++ b/framework/src/play/classloading/ApplicationCompiler.java @@ -36,9 +36,12 @@ public class ApplicationCompiler { Map packagesCache = new HashMap<>(); ApplicationClasses applicationClasses; Map settings; - + /** * Try to guess the magic configuration options + * + * @param applicationClasses + * The application classes container */ public ApplicationCompiler(ApplicationClasses applicationClasses) { this.applicationClasses = applicationClasses; @@ -67,7 +70,6 @@ public ApplicationCompiler(ApplicationClasses applicationClasses) { this.settings.put(CompilerOptions.OPTION_Compliance, javaVersion); this.settings.put(CompilerOptions.OPTION_MethodParametersAttribute, CompilerOptions.GENERATE); } - /** * Something to compile @@ -120,17 +122,18 @@ public char[][] getPackageName() { @Override public boolean ignoreOptionalProblems() { - // TODO Auto-generated method stub return false; } } /** * Please compile this className + * + * @param classNames + * Arrays of the class name to compile */ @SuppressWarnings("deprecation") public void compile(String[] classNames) { - ICompilationUnit[] compilationUnits = new CompilationUnit[classNames.length]; for (int i = 0; i < classNames.length; i++) { compilationUnits[i] = new CompilationUnit(classNames[i]); diff --git a/framework/src/play/classloading/enhancers/Enhancer.java b/framework/src/play/classloading/enhancers/Enhancer.java index d650c69301..d2c3abd69b 100644 --- a/framework/src/play/classloading/enhancers/Enhancer.java +++ b/framework/src/play/classloading/enhancers/Enhancer.java @@ -1,15 +1,16 @@ package play.classloading.enhancers; -import java.io.File; import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; -import java.io.FileInputStream; import java.lang.annotation.Annotation; import java.net.MalformedURLException; import java.net.URL; import java.util.HashMap; import java.util.Map; + import javassist.ClassPath; import javassist.ClassPool; import javassist.CtClass; @@ -19,8 +20,8 @@ import javassist.NotFoundException; import javassist.bytecode.AnnotationsAttribute; import javassist.bytecode.annotation.MemberValue; -import play.Play; import play.Logger; +import play.Play; import play.classloading.ApplicationClasses.ApplicationClass; /** @@ -33,7 +34,7 @@ public abstract class Enhancer { public Enhancer() { this.classPool = newClassPool(); } - + public static ClassPool newClassPool() { ClassPool classPool = new ClassPool(); classPool.appendSystemPath(); @@ -44,6 +45,12 @@ public static ClassPool newClassPool() { /** * Construct a javassist CtClass from an application class. + * + * @param applicationClass + * The application class to construct + * @return The javassist CtClass construct from the application class + * @throws IOException + * if problem occurred during construction */ public CtClass makeClass(ApplicationClass applicationClass) throws IOException { return classPool.makeClass(new ByteArrayInputStream(applicationClass.enhancedByteCode)); @@ -51,6 +58,11 @@ public CtClass makeClass(ApplicationClass applicationClass) throws IOException { /** * The magic happen here... + * + * @param applicationClass + * The application class to construct + * @throws Exception + * if problem occurred during construction */ public abstract void enhanceThisClass(ApplicationClass applicationClass) throws Exception; @@ -62,17 +74,17 @@ public static class ApplicationClassesClasspath implements ClassPath { @Override public InputStream openClassfile(String className) throws NotFoundException { - if(Play.usePrecompiled) { + if (Play.usePrecompiled) { try { File file = Play.getFile("precompiled/java/" + className.replace(".", "/") + ".class"); return new FileInputStream(file); - } catch(Exception e) { + } catch (Exception e) { Logger.error("Missing class %s", className); } } ApplicationClass appClass = Play.classes.getApplicationClass(className); - if ( appClass.enhancedByteCode == null) { + if (appClass.enhancedByteCode == null) { throw new RuntimeException("Trying to visit uncompiled class while enhancing. Uncompiled class: " + className); } @@ -98,11 +110,15 @@ public void close() { } /** - * Test if a class has the provided annotation - * @param ctClass the javassist class representation - * @param annotation fully qualified name of the annotation class eg."javax.persistence.Entity" + * Test if a class has the provided annotation + * + * @param ctClass + * the javassist class representation + * @param annotation + * fully qualified name of the annotation class eg."javax.persistence.Entity" * @return true if class has the annotation * @throws java.lang.ClassNotFoundException + * if class not found */ protected boolean hasAnnotation(CtClass ctClass, String annotation) throws ClassNotFoundException { for (Object object : ctClass.getAvailableAnnotations()) { @@ -115,12 +131,16 @@ protected boolean hasAnnotation(CtClass ctClass, String annotation) throws Class } /** - * Test if a field has the provided annotation - * @param ctField the javassist field representation - * @param annotation fully qualified name of the annotation class eg."javax.persistence.Entity" + * Test if a field has the provided annotation + * + * @param ctField + * the javassist field representation + * @param annotation + * fully qualified name of the annotation class eg."javax.persistence.Entity" * @return true if field has the annotation * @throws java.lang.ClassNotFoundException - */ + * if class not found + */ protected boolean hasAnnotation(CtField ctField, String annotation) throws ClassNotFoundException { for (Object object : ctField.getAvailableAnnotations()) { Annotation ann = (Annotation) object; @@ -130,13 +150,17 @@ protected boolean hasAnnotation(CtField ctField, String annotation) throws Class } return false; } - + /** * Test if a method has the provided annotation - * @param ctMethod the javassist method representation - * @param annotation fully qualified name of the annotation class eg."javax.persistence.Entity" + * + * @param ctMethod + * the javassist method representation + * @param annotation + * fully qualified name of the annotation class eg."javax.persistence.Entity" * @return true if field has the annotation * @throws java.lang.ClassNotFoundException + * if class not found */ protected boolean hasAnnotation(CtMethod ctMethod, String annotation) throws ClassNotFoundException { for (Object object : ctMethod.getAvailableAnnotations()) { @@ -150,9 +174,18 @@ protected boolean hasAnnotation(CtMethod ctMethod, String annotation) throws Cla /** * Create a new annotation to be dynamically inserted in the byte code. + * + * @param attribute + * annotation attribute + * @param annotationType + * Annotation + * @param members + * Member of the annotation */ - protected static void createAnnotation(AnnotationsAttribute attribute, Class annotationType, Map members) { - javassist.bytecode.annotation.Annotation annotation = new javassist.bytecode.annotation.Annotation(annotationType.getName(), attribute.getConstPool()); + protected static void createAnnotation(AnnotationsAttribute attribute, Class annotationType, + Map members) { + javassist.bytecode.annotation.Annotation annotation = new javassist.bytecode.annotation.Annotation(annotationType.getName(), + attribute.getConstPool()); for (Map.Entry member : members.entrySet()) { annotation.addMemberValue(member.getKey(), member.getValue()); } @@ -161,16 +194,26 @@ protected static void createAnnotation(AnnotationsAttribute attribute, Class annotationType) { createAnnotation(attribute, annotationType, new HashMap()); } /** * Retrieve all class annotations. + * + * @param ctClass + * The given class + * @return All class annotations */ protected static AnnotationsAttribute getAnnotations(CtClass ctClass) { - AnnotationsAttribute annotationsAttribute = (AnnotationsAttribute) ctClass.getClassFile().getAttribute(AnnotationsAttribute.visibleTag); + AnnotationsAttribute annotationsAttribute = (AnnotationsAttribute) ctClass.getClassFile() + .getAttribute(AnnotationsAttribute.visibleTag); if (annotationsAttribute == null) { annotationsAttribute = new AnnotationsAttribute(ctClass.getClassFile().getConstPool(), AnnotationsAttribute.visibleTag); ctClass.getClassFile().addAttribute(annotationsAttribute); @@ -180,9 +223,14 @@ protected static AnnotationsAttribute getAnnotations(CtClass ctClass) { /** * Retrieve all field annotations. - */ + * + * @param ctField + * The given field + * @return All field annotations. + */ protected static AnnotationsAttribute getAnnotations(CtField ctField) { - AnnotationsAttribute annotationsAttribute = (AnnotationsAttribute) ctField.getFieldInfo().getAttribute(AnnotationsAttribute.visibleTag); + AnnotationsAttribute annotationsAttribute = (AnnotationsAttribute) ctField.getFieldInfo() + .getAttribute(AnnotationsAttribute.visibleTag); if (annotationsAttribute == null) { annotationsAttribute = new AnnotationsAttribute(ctField.getFieldInfo().getConstPool(), AnnotationsAttribute.visibleTag); ctField.getFieldInfo().addAttribute(annotationsAttribute); @@ -192,9 +240,14 @@ protected static AnnotationsAttribute getAnnotations(CtField ctField) { /** * Retrieve all method annotations. - */ + * + * @param ctMethod + * The given methods + * @return all method annotations. + */ protected static AnnotationsAttribute getAnnotations(CtMethod ctMethod) { - AnnotationsAttribute annotationsAttribute = (AnnotationsAttribute) ctMethod.getMethodInfo().getAttribute(AnnotationsAttribute.visibleTag); + AnnotationsAttribute annotationsAttribute = (AnnotationsAttribute) ctMethod.getMethodInfo() + .getAttribute(AnnotationsAttribute.visibleTag); if (annotationsAttribute == null) { annotationsAttribute = new AnnotationsAttribute(ctMethod.getMethodInfo().getConstPool(), AnnotationsAttribute.visibleTag); ctMethod.getMethodInfo().addAttribute(annotationsAttribute); @@ -203,8 +256,8 @@ protected static AnnotationsAttribute getAnnotations(CtMethod ctMethod) { } boolean isScalaObject(CtClass ctClass) throws Exception { - for(CtClass i : ctClass.getInterfaces()) { - if(i.getName().equals("scala.ScalaObject")) { + for (CtClass i : ctClass.getInterfaces()) { + if (i.getName().equals("scala.ScalaObject")) { return true; } } @@ -218,5 +271,4 @@ boolean isScala(ApplicationClass app) { boolean isAnon(ApplicationClass app) { return app.name.contains("$anonfun$") || app.name.contains("$anon$"); } - -} +} \ No newline at end of file diff --git a/framework/src/play/classloading/enhancers/LocalvariablesNamesEnhancer.java b/framework/src/play/classloading/enhancers/LocalvariablesNamesEnhancer.java index b277ed44de..48d1b88df7 100644 --- a/framework/src/play/classloading/enhancers/LocalvariablesNamesEnhancer.java +++ b/framework/src/play/classloading/enhancers/LocalvariablesNamesEnhancer.java @@ -1,14 +1,22 @@ package play.classloading.enhancers; +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Stack; + import javassist.CtClass; import javassist.CtMethod; -import javassist.bytecode.*; +import javassist.bytecode.Bytecode; +import javassist.bytecode.CodeAttribute; +import javassist.bytecode.CodeIterator; +import javassist.bytecode.LocalVariableAttribute; +import javassist.bytecode.Opcode; import play.Logger; import play.classloading.ApplicationClasses.ApplicationClass; -import java.lang.reflect.Field; -import java.util.*; - /** * Track names of local variables ... */ @@ -21,7 +29,8 @@ public void enhanceThisClass(ApplicationClass applicationClass) throws Exception } CtClass ctClass = makeClass(applicationClass); - if (!ctClass.subtypeOf(classPool.get(LocalVariablesSupport.class.getName())) && !ctClass.getName().matches("^controllers\\..*\\$class$")) { + if (!ctClass.subtypeOf(classPool.get(LocalVariablesSupport.class.getName())) + && !ctClass.getName().matches("^controllers\\..*\\$class$")) { return; } @@ -71,7 +80,7 @@ public void enhanceThisClass(ApplicationClass applicationClass) throws Exception CodeIterator codeIterator = codeAttribute.iterator(); codeIterator.move(pc); pc = codeIterator.next(); - + Bytecode b = makeBytecodeForLVStore(method, localVariableAttribute.signature(i), name, localVariableAttribute.index(i)); codeIterator.insert(pc, b.get()); codeAttribute.setMaxStack(codeAttribute.computeMaxStack()); @@ -95,9 +104,12 @@ public void enhanceThisClass(ApplicationClass applicationClass) throws Exception // Si c'est un store de la variable en cours d'examination // et que c'est dans la frame d'utilisation de cette variable on trace l'affectation. - // (en fait la frame commence à localVariableAttribute.startPc(i)-1 qui est la première affectation - // mais aussi l'initialisation de la variable qui est deja tracé plus haut, donc on commence à localVariableAttribute.startPc(i)) - if (varNumber == localVariableAttribute.index(i) && index < localVariableAttribute.startPc(i) + localVariableAttribute.codeLength(i)) { + // (en fait la frame commence à localVariableAttribute.startPc(i)-1 qui est la première + // affectation + // mais aussi l'initialisation de la variable qui est deja tracé plus haut, donc on commence à + // localVariableAttribute.startPc(i)) + if (varNumber == localVariableAttribute.index(i) + && index < localVariableAttribute.startPc(i) + localVariableAttribute.codeLength(i)) { b = makeBytecodeForLVStore(method, localVariableAttribute.signature(i), aliasedName, varNumber); codeIterator.insertEx(b.get()); codeAttribute.setMaxStack(codeAttribute.computeMaxStack()); @@ -120,30 +132,31 @@ public void enhanceThisClass(ApplicationClass applicationClass) throws Exception ctClass.defrost(); } - + static Bytecode makeBytecodeForLVStore(CtMethod method, String sig, String name, int slot) { Bytecode b = new Bytecode(method.getMethodInfo().getConstPool()); b.addLdc(name); - if("I".equals(sig) || "B".equals(sig) || "C".equals(sig) || "S".equals(sig) || "Z".equals(sig)) + if ("I".equals(sig) || "B".equals(sig) || "C".equals(sig) || "S".equals(sig) || "Z".equals(sig)) b.addIload(slot); - else if("F".equals(sig)) + else if ("F".equals(sig)) b.addFload(slot); - else if("J".equals(sig)) + else if ("J".equals(sig)) b.addLload(slot); - else if("D".equals(sig)) + else if ("D".equals(sig)) b.addDload(slot); else b.addAload(slot); - + String localVarDescriptor = sig; - if(!"B".equals(sig) && !"C".equals(sig) && !"D".equals(sig) && !"F".equals(sig) && - !"I".equals(sig) && !"J".equals(sig) && !"S".equals(sig) && !"Z".equals(sig)) + if (!"B".equals(sig) && !"C".equals(sig) && !"D".equals(sig) && !"F".equals(sig) && !"I".equals(sig) && !"J".equals(sig) + && !"S".equals(sig) && !"Z".equals(sig)) localVarDescriptor = "Ljava/lang/Object;"; Logger.trace("for variable '%s' in slot=%s, sig was '%s' and is now '%s'", name, slot, sig, localVarDescriptor); - b.addInvokestatic("play.classloading.enhancers.LocalvariablesNamesEnhancer$LocalVariablesNamesTracer", "addVariable", "(Ljava/lang/String;"+localVarDescriptor+")V"); - + b.addInvokestatic("play.classloading.enhancers.LocalvariablesNamesEnhancer$LocalVariablesNamesTracer", "addVariable", + "(Ljava/lang/String;" + localVarDescriptor + ")V"); + return b; } @@ -252,19 +265,20 @@ public static Object getLocalVariable(String variable) { public static Stack> getLocalVariablesStateBeforeAwait() { Stack> state = localVariables.get(); - // must clear the ThreadLocal to prevent destroying the state when exit() is called due to continuations-suspend + // must clear the ThreadLocal to prevent destroying the state when exit() is called due to + // continuations-suspend localVariables.set(new Stack>()); return state; } public static void setLocalVariablesStateAfterAwait(Stack> state) { - if (state==null) { + if (state == null) { state = new Stack<>(); } - localVariables.set( state ); + localVariables.set(state); } } - + static final Map storeByCode = new HashMap<>(); /* @@ -305,11 +319,15 @@ public static void setLocalVariablesStateAfterAwait(Stack> s /** * Debug utility. Display a byte code op as plain text. + * + * @param op + * The given byte code */ public static void printOp(int op) { try { for (Field f : Opcode.class.getDeclaredFields()) { - if (java.lang.reflect.Modifier.isStatic(f.getModifiers()) && java.lang.reflect.Modifier.isPublic(f.getModifiers()) && f.getInt(null) == op) { + if (java.lang.reflect.Modifier.isStatic(f.getModifiers()) && java.lang.reflect.Modifier.isPublic(f.getModifiers()) + && f.getInt(null) == op) { System.out.println(op + " " + f.getName()); } } diff --git a/framework/src/play/data/binding/AnnotationHelper.java b/framework/src/play/data/binding/AnnotationHelper.java index 3f186867e0..8b5153ce3f 100644 --- a/framework/src/play/data/binding/AnnotationHelper.java +++ b/framework/src/play/data/binding/AnnotationHelper.java @@ -19,10 +19,12 @@ public class AnnotationHelper { * It can be something like As(lang={"fr,de","*"}, value={"dd-MM-yyyy","MM-dd-yyyy"}) * * @param annotations + * Annotations associated with on the date * @param value + * The formated date * @return null if it cannot be converted because there is no annotation. * @throws ParseException - * + * if problem occurred during parsing the date */ public static Date getDateAs(Annotation[] annotations, String value) throws ParseException { // Look up for the BindAs annotation @@ -35,7 +37,7 @@ public static Date getDateAs(Annotation[] annotations, String value) throws Pars Locale locale = Lang.getLocale(); String format = as.value()[0]; // According to Binder.java line 328 : Fixtures can use (iso) dates as default - if(format != null && format.equals(Fixtures.PROFILE_NAME)){ + if (format != null && format.equals(Fixtures.PROFILE_NAME)) { format = DateBinder.ISO8601; locale = null; } else if (!StringUtils.isEmpty(format)) { @@ -50,7 +52,7 @@ public static Date getDateAs(Annotation[] annotations, String value) throws Pars if (StringUtils.isEmpty(format)) { format = I18N.getDateFormat(); } - SimpleDateFormat sdf = locale != null ? new SimpleDateFormat(format, locale) : new SimpleDateFormat(format); + SimpleDateFormat sdf = locale != null ? new SimpleDateFormat(format, locale) : new SimpleDateFormat(format); sdf.setLenient(false); return sdf.parse(value); } @@ -85,7 +87,7 @@ public static Tuple getLocale(String[] langs) { * Contains the index of the locale inside the @As */ private static class Tuple { - + public int index = -1; public Locale locale; diff --git a/framework/src/play/data/binding/Binder.java b/framework/src/play/data/binding/Binder.java index 1d6258ca45..124c90f160 100644 --- a/framework/src/play/data/binding/Binder.java +++ b/framework/src/play/data/binding/Binder.java @@ -1,23 +1,52 @@ package play.data.binding; +import java.io.File; +import java.lang.annotation.Annotation; +import java.lang.reflect.Array; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.math.BigDecimal; +import java.text.ParseException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Calendar; +import java.util.Collection; +import java.util.Comparator; +import java.util.Date; +import java.util.EnumSet; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Set; +import java.util.SortedSet; +import java.util.TreeSet; + import org.apache.commons.lang.StringUtils; import org.joda.time.DateTime; + import play.Logger; import play.Play; import play.data.Upload; -import play.data.binding.types.*; +import play.data.binding.types.BinaryBinder; +import play.data.binding.types.ByteArrayArrayBinder; +import play.data.binding.types.ByteArrayBinder; +import play.data.binding.types.CalendarBinder; +import play.data.binding.types.DateBinder; +import play.data.binding.types.DateTimeBinder; +import play.data.binding.types.FileArrayBinder; +import play.data.binding.types.FileBinder; +import play.data.binding.types.LocaleBinder; +import play.data.binding.types.UploadArrayBinder; +import play.data.binding.types.UploadBinder; import play.data.validation.Validation; import play.db.Model; import play.exceptions.UnexpectedException; -import java.io.File; -import java.lang.annotation.Annotation; -import java.lang.reflect.*; -import java.math.BigDecimal; -import java.text.ParseException; -import java.util.*; - - /** * The binder try to convert String values to Java objects. */ @@ -48,9 +77,15 @@ public abstract class Binder { * * E.g. @{code Binder.register(BigDecimal.class, new MyBigDecimalBinder());} * - * NB! Do not forget to UNREGISTER your custom binder when applications is reloaded (most probably in method onApplicationStop()). - * Otherwise you will have a memory leak. + * NB! Do not forget to UNREGISTER your custom binder when applications is reloaded (most probably in method + * onApplicationStop()). Otherwise you will have a memory leak. * + * @param clazz + * The class to register + * @param typeBinder + * The custom binder + * @param + * The Class type to register * @see #unregister(java.lang.Class) */ public static void register(Class clazz, TypeBinder typeBinder) { @@ -59,6 +94,11 @@ public static void register(Class clazz, TypeBinder typeBinder) { /** * Remove custom binder that was add with method #register(java.lang.Class, play.data.binding.TypeBinder) + * + * @param clazz + * The class to remove the custom binder + * @param + * The Class type to register */ public static void unregister(Class clazz) { supportedTypes.remove(clazz); @@ -88,6 +128,14 @@ public MethodAndParamInfo(Object objectInstance, Method method, int parameterInd /** * Deprecated. Use bindBean() instead. + * + * @param o + * Object to bind + * @param name + * Name of the object + * @param params + * List of the parameters + * @return : The binding object */ @Deprecated public static Object bind(Object o, String name, Map params) { @@ -106,7 +154,8 @@ public static Object bind(RootParamNode parentParamNode, String name, Class c return bind(parentParamNode, name, clazz, type, annotations, null); } - public static Object bind(RootParamNode parentParamNode, String name, Class clazz, Type type, Annotation[] annotations, MethodAndParamInfo methodAndParamInfo) { + public static Object bind(RootParamNode parentParamNode, String name, Class clazz, Type type, Annotation[] annotations, + MethodAndParamInfo methodAndParamInfo) { ParamNode paramNode = parentParamNode.getChild(name, true); Object result = null; @@ -136,7 +185,8 @@ public static Object bind(RootParamNode parentParamNode, String name, Class c if (methodAndParamInfo != null) { try { Method method = methodAndParamInfo.method; - Method defaultMethod = method.getDeclaringClass().getDeclaredMethod(method.getName() + "$default$" + methodAndParamInfo.parameterIndex); + Method defaultMethod = method.getDeclaringClass() + .getDeclaredMethod(method.getName() + "$default$" + methodAndParamInfo.parameterIndex); return defaultMethod.invoke(methodAndParamInfo.objectInstance); } catch (NoSuchMethodException ignore) { } catch (Exception e) { @@ -173,7 +223,6 @@ public static Object bind(RootParamNode parentParamNode, String name, Class c } - protected static Object internalBind(ParamNode paramNode, Class clazz, Type type, BindingAnnotations bindingAnnotations) { if (paramNode == null) { @@ -202,14 +251,16 @@ protected static Object internalBind(ParamNode paramNode, Class clazz, Type t return bindCollection(clazz, type, paramNode, bindingAnnotations); } - Object directBindResult = internalDirectBind(paramNode.getOriginalKey(), bindingAnnotations.annotations, paramNode.getFirstValue(clazz), clazz, type); - + Object directBindResult = internalDirectBind(paramNode.getOriginalKey(), bindingAnnotations.annotations, + paramNode.getFirstValue(clazz), clazz, type); + if (directBindResult != DIRECTBINDING_NO_RESULT) { // we found a value/result when direct binding return directBindResult; } - // Must do the default array-check after direct binding, since some custom-binders checks for specific arrays + // Must do the default array-check after direct binding, since some custom-binders checks for specific + // arrays if (clazz.isArray()) { return bindArray(clazz, paramNode, bindingAnnotations); } @@ -267,7 +318,8 @@ private static Object bindArray(Class clazz, ParamNode paramNode, BindingAnno for (int i = 0; i < size; i++) { String thisValue = values[i]; try { - Array.set(array, i - invalidItemsCount, directBind(paramNode.getOriginalKey(), bindingAnnotations.annotations, thisValue, componentType, componentType)); + Array.set(array, i - invalidItemsCount, directBind(paramNode.getOriginalKey(), bindingAnnotations.annotations, + thisValue, componentType, componentType)); } catch (Exception e) { Logger.debug("Bad item #%s: %s", i, e); invalidItemsCount++; @@ -326,6 +378,13 @@ private static T createNewInstance(Class clazz) { /** * Invokes the plugins before using the internal bindBean. + * + * @param rootParamNode + * List of parameters + * @param name + * The object name + * @param bean + * the bean object */ public static void bindBean(RootParamNode rootParamNode, String name, Object bean) { @@ -348,6 +407,13 @@ public static void bindBean(RootParamNode rootParamNode, String name, Object bea /** * Does NOT invoke plugins + * + * @param paramNode + * List of parameters + * @param bean + * the bean object + * @param annotations + * annotations associated with the object */ public static void bindBean(ParamNode paramNode, Object bean, Annotation[] annotations) { internalBindBean(paramNode, bean, new BindingAnnotations(annotations)); @@ -407,7 +473,8 @@ private static Object bindMap(Type type, ParamNode paramNode, BindingAnnotations for (ParamNode child : paramNode.getAllChildren()) { try { - Object keyObject = directBind(paramNode.getOriginalKey(), bindingAnnotations.annotations, child.getName(), keyClass, keyClass); + Object keyObject = directBind(paramNode.getOriginalKey(), bindingAnnotations.annotations, child.getName(), keyClass, + keyClass); Object valueObject = internalBind(child, valueClass, valueClass, bindingAnnotations); if (valueObject == NO_BINDING || valueObject == MISSING) { valueObject = null; @@ -443,7 +510,7 @@ private static Object bindCollection(Class clazz, Type type, ParamNode paramN Type componentType = String.class; if (type instanceof ParameterizedType) { componentType = ((ParameterizedType) type).getActualTypeArguments()[0]; - if(componentType instanceof ParameterizedType) { + if (componentType instanceof ParameterizedType) { componentClass = (Class) ((ParameterizedType) componentType).getRawType(); } else { componentClass = (Class) componentType; @@ -479,10 +546,11 @@ private static Object bindCollection(Class clazz, Type type, ParamNode paramN boolean hasMissing = false; for (int i = 0; i < values.length; i++) { try { - Object value = internalDirectBind(paramNode.getOriginalKey(), bindingAnnotations.annotations, values[i], componentClass, componentType); - if ( value == DIRECTBINDING_NO_RESULT) { - hasMissing = true; - } else { + Object value = internalDirectBind(paramNode.getOriginalKey(), bindingAnnotations.annotations, values[i], componentClass, + componentType); + if (value == DIRECTBINDING_NO_RESULT) { + hasMissing = true; + } else { l.add(value); } } catch (Exception e) { @@ -490,10 +558,10 @@ private static Object bindCollection(Class clazz, Type type, ParamNode paramN logBindingNormalFailure(paramNode, e); // TODO debug or error? } } - if(hasMissing && l.size() == 0){ + if (hasMissing && l.size() == 0) { return MISSING; } - return l; + return l; } Collection r = (Collection) createNewInstance(clazz); @@ -550,21 +618,54 @@ public int compare(String arg0, String arg1) { } /** + * Bind a object + * + * @param value + * value to bind + * @param clazz + * class of the object * @return The binding object + * @throws Exception + * if problem occurred during binding */ public static Object directBind(String value, Class clazz) throws Exception { return directBind(null, value, clazz, null); } /** + * Bind a object + * + * @param name + * name of the object + * @param annotations + * annotation on the object + * @param value + * Value to bind + * @param clazz + * The class of the object + * * @return The binding object + * @throws Exception + * if problem occurred during binding */ public static Object directBind(String name, Annotation[] annotations, String value, Class clazz) throws Exception { return directBind(name, annotations, value, clazz, null); } /** + * Bind a object + * + * @param annotations + * annotation on the object + * @param value + * value to bind + * @param clazz + * class of the object + * @param type + * type to bind * @return The binding object + * @throws Exception + * if problem occurred during binding */ public static Object directBind(Annotation[] annotations, String value, Class clazz, Type type) throws Exception { return directBind(null, annotations, value, clazz, type); @@ -572,13 +673,25 @@ public static Object directBind(Annotation[] annotations, String value, Class /** * This method calls the user's defined binders prior to bind simple type - * + * + * @param name + * name of the object + * @param annotations + * annotation on the object + * @param value + * value to bind + * @param clazz + * class of the object + * @param type + * type to bind * @return The binding object + * @throws Exception + * if problem occurred during binding */ public static Object directBind(String name, Annotation[] annotations, String value, Class clazz, Type type) throws Exception { // calls the direct binding and returns null if no value could be resolved.. Object r = internalDirectBind(name, annotations, value, clazz, type); - if ( r == DIRECTBINDING_NO_RESULT) { + if (r == DIRECTBINDING_NO_RESULT) { return null; } else { return r; @@ -587,7 +700,8 @@ public static Object directBind(String name, Annotation[] annotations, String va // If internalDirectBind was not able to bind it, it returns a special variable instance: DIRECTBIND_MISSING // Needs this because sometimes we need to know if no value was returned.. - private static Object internalDirectBind(String name, Annotation[] annotations, String value, Class clazz, Type type) throws Exception { + private static Object internalDirectBind(String name, Annotation[] annotations, String value, Class clazz, Type type) + throws Exception { boolean nullOrEmpty = value == null || value.trim().length() == 0; if (annotations != null) { diff --git a/framework/src/play/data/binding/TypeUnbinder.java b/framework/src/play/data/binding/TypeUnbinder.java index 71986dd1bf..0ac06e6f37 100644 --- a/framework/src/play/data/binding/TypeUnbinder.java +++ b/framework/src/play/data/binding/TypeUnbinder.java @@ -5,19 +5,28 @@ /** * Supported type for unbinding. This interface is used to implement custom unbinders. + * + * @param + * Type of the unbinder * */ public interface TypeUnbinder { - - /** + + /** * @param result - * @param src the object you want to unbind - * @param srcClazz The class of the object you want to associate the value with - * @param name the name of you parameter ie myparam for a simple param but can also be a complex one : mybean.address.street - * @param annotations An array of annotation that may be bound to your method parameter or your bean property - * @return true si unbinder is successful, otherwise false and will use the default unbinder + * The result container + * @param src + * the object you want to unbind + * @param srcClazz + * The class of the object you want to associate the value with + * @param name + * the name of you parameter ie myparam for a simple param but can also be a complex one : + * mybean.address.street + * @param annotations + * An array of annotation that may be bound to your method parameter or your bean property + * @return true if unwinder is successful, otherwise false and will use the default unbinder * @throws Exception + * if problem occurred */ boolean unBind(Map result, Object src, Class srcClazz, String name, Annotation[] annotations) throws Exception; - } diff --git a/framework/src/play/data/parsing/ApacheMultipartParser.java b/framework/src/play/data/parsing/ApacheMultipartParser.java index 61c22ddcef..6603bf254d 100644 --- a/framework/src/play/data/parsing/ApacheMultipartParser.java +++ b/framework/src/play/data/parsing/ApacheMultipartParser.java @@ -1,6 +1,28 @@ package play.data.parsing; -import org.apache.commons.fileupload.*; +import static org.apache.commons.io.FileUtils.readFileToByteArray; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.UnsupportedEncodingException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.NoSuchElementException; + +import org.apache.commons.fileupload.FileItem; +import org.apache.commons.fileupload.FileItemHeaders; +import org.apache.commons.fileupload.FileItemIterator; +import org.apache.commons.fileupload.FileItemStream; +import org.apache.commons.fileupload.FileUploadBase; +import org.apache.commons.fileupload.FileUploadException; +import org.apache.commons.fileupload.ParameterParser; +import org.apache.commons.fileupload.RequestContext; import org.apache.commons.fileupload.disk.DiskFileItem; import org.apache.commons.fileupload.util.Closeable; import org.apache.commons.fileupload.util.LimitedInputStream; @@ -9,6 +31,7 @@ import org.apache.commons.io.FileUtils; import org.apache.commons.io.FilenameUtils; import org.apache.commons.io.output.DeferredFileOutputStream; + import play.Logger; import play.Play; import play.data.FileUpload; @@ -18,14 +41,8 @@ import play.mvc.Http.Request; import play.utils.HTTP; -import java.io.*; -import java.util.*; - -import static org.apache.commons.io.FileUtils.readFileToByteArray; - /** - * From Apache commons fileupload. - * http://commons.apache.org/fileupload/ + * From Apache commons fileupload. http://commons.apache.org/fileupload/ */ public class ApacheMultipartParser extends DataParser { @@ -46,35 +63,33 @@ private static void putMapEntry(Map map, String name, String v /* * Copyright 2001-2004 The Apache Software Foundation * - * 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 + * 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 + * 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. + * 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. * - *

The default implementation of the - * {@link org.apache.commons.fileupload.FileItem FileItem} interface. + *

The default implementation of the {@link org.apache.commons.fileupload.FileItem FileItem} interface. * - *

After retrieving an instance of this class from a {@link - * org.apache.commons.fileupload.DiskFileUpload DiskFileUpload} instance (see - * {@link org.apache.commons.fileupload.DiskFileUpload - * #parseRequest(javax.servlet.http.HttpServletRequest)}), you may - * either request all contents of file at once using {@link #get()} or - * request an {@link java.io.InputStream InputStream} with - * {@link #getInputStream()} and process the file without attempting to load - * it into memory, which may come handy with large files. + *

After retrieving an instance of this class from a {@link org.apache.commons.fileupload.DiskFileUpload + * DiskFileUpload} instance (see {@link org.apache.commons.fileupload.DiskFileUpload + * #parseRequest(javax.servlet.http.HttpServletRequest)}), you may either request all contents of file at once using + * {@link #get()} or request an {@link java.io.InputStream InputStream} with {@link #getInputStream()} and process + * the file without attempting to load it into memory, which may come handy with large files. * * @author Rafal Krzewski + * * @author Sean Legassick + * * @author Jason van Zyl + * * @author John McNally + * * @author Martin Cooper + * * @author Sean C. Sullivan * * @since FileUpload 1.1 @@ -91,10 +106,9 @@ public static class AutoFileItem implements FileItem { // ----------------------------------------------------- Manifest constants /** - * Default content charset to be used when no explicit charset - * parameter is provided by the sender. Media subtypes of the - * "text" type are defined to have a default charset value of - * "ISO-8859-1" when received via HTTP. + * Default content charset to be used when no explicit charset parameter is provided by the sender. Media + * subtypes of the "text" type are defined to have a default charset value of "ISO-8859-1" when received via + * HTTP. */ public static final String DEFAULT_CHARSET = "ISO-8859-1"; /** @@ -112,8 +126,7 @@ public static class AutoFileItem implements FileItem { */ private String fieldName; /** - * The content type passed by the browser, or null if - * not defined. + * The content type passed by the browser, or null if not defined. */ private String contentType; /** @@ -140,9 +153,9 @@ public static class AutoFileItem implements FileItem { * Output stream for this item. */ private DeferredFileOutputStream dfos; - + /** - * The file items headers. + * The file items headers. */ private FileItemHeaders headers; @@ -157,16 +170,14 @@ public AutoFileItem(FileItemStream stream) { // ------------------------------- Methods from javax.activation.DataSource /** - * Returns an {@link java.io.InputStream InputStream} that can be - * used to retrieve the contents of the file. + * Returns an {@link java.io.InputStream InputStream} that can be used to retrieve the contents of the file. * - * @return An {@link java.io.InputStream InputStream} that can be - * used to retrieve the contents of the file. - * @throws IOException if an error occurs. + * @return An {@link java.io.InputStream InputStream} that can be used to retrieve the contents of the file. + * @throws IOException + * if an error occurs. */ @Override - public InputStream getInputStream() - throws IOException { + public InputStream getInputStream() throws IOException { if (!dfos.isInMemory()) { return new FileInputStream(dfos.getFile()); } @@ -178,11 +189,9 @@ public InputStream getInputStream() } /** - * Returns the content type passed by the agent or null if - * not defined. + * Returns the content type passed by the agent or null if not defined. * - * @return The content type passed by the agent or null if - * not defined. + * @return The content type passed by the agent or null if not defined. */ @Override public String getContentType() { @@ -190,18 +199,16 @@ public String getContentType() { } /** - * Returns the content charset passed by the agent or null if - * not defined. + * Returns the content charset passed by the agent or null if not defined. * - * @return The content charset passed by the agent or null if - * not defined. + * @return The content charset passed by the agent or null if not defined. */ public String getCharSet() { ParameterParser parser = new ParameterParser(); parser.setLowerCaseNames(true); // Parameter parser can handle null input Map params = parser.parse(getContentType(), ';'); - return (String) params.get("charset"); + return params.get("charset"); } /** @@ -216,11 +223,9 @@ public String getName() { // ------------------------------------------------------- FileItem methods /** - * Provides a hint as to whether or not the file contents will be read - * from memory. + * Provides a hint as to whether or not the file contents will be read from memory. * - * @return true if the file contents will be read - * from memory; false otherwise. + * @return true if the file contents will be read from memory; false otherwise. */ @Override public boolean isInMemory() { @@ -244,9 +249,8 @@ public long getSize() { } /** - * Returns the contents of the file as an array of bytes. If the - * contents of the file were not yet cached in memory, they will be - * loaded from the disk storage and cached. + * Returns the contents of the file as an array of bytes. If the contents of the file were not yet cached in + * memory, they will be loaded from the disk storage and cached. * * @return The contents of the file as an array of bytes. */ @@ -267,28 +271,29 @@ public byte[] get() { } /** - * Returns the contents of the file as a String, using the specified - * encoding. This method uses {@link #get()} to retrieve the - * contents of the file. + * Returns the contents of the file as a String, using the specified encoding. This method uses {@link #get()} + * to retrieve the contents of the file. * - * @param charset The charset to use. + * @param charset + * The charset to use. * @return The contents of the file, as a string. - * @throws UnsupportedEncodingException if the requested character - * encoding is not available. + * @throws UnsupportedEncodingException + * if the requested character encoding is not available. */ @Override - public String getString(String charset) - throws UnsupportedEncodingException { + public String getString(String charset) throws UnsupportedEncodingException { return new String(get(), charset); } /** - * Returns the contents of the file as a String, using the default - * character encoding. This method uses {@link #get()} to retrieve the - * contents of the file. - * + * Returns the contents of the file as a String, using the default character encoding. This method uses + * {@link #get()} to retrieve the contents of the file. + *

+ * + * @play.todo Note: TODO Consider making this method throw UnsupportedEncodingException . + *

+ * * @return The contents of the file, as a string. - * @todo Consider making this method throw UnsupportedEncodingException. */ @Override public String getString() { @@ -305,23 +310,21 @@ public String getString() { } /** - * A convenience method to write an uploaded item to disk. The client code - * is not concerned with whether or not the item is stored in memory, or on - * disk in a temporary location. They just want to write the uploaded item + * A convenience method to write an uploaded item to disk. The client code is not concerned with whether or not + * the item is stored in memory, or on disk in a temporary location. They just want to write the uploaded item * to a file. *

- * This implementation first attempts to rename the uploaded item to the - * specified destination file, if the item was originally written to disk. - * Otherwise, the data will be copied to the specified file. + * This implementation first attempts to rename the uploaded item to the specified destination file, if the item + * was originally written to disk. Otherwise, the data will be copied to the specified file. *

- * This method is only guaranteed to work once, the first time it - * is invoked for a particular item. This is because, in the event that the - * method renames a temporary file, that file will no longer be available + * This method is only guaranteed to work once, the first time it is invoked for a particular item. + * This is because, in the event that the method renames a temporary file, that file will no longer be available * to copy or rename again at a later time. * - * @param file The File into which the uploaded item should - * be stored. - * @throws Exception if an error occurs. + * @param file + * The File into which the uploaded item should be stored. + * @throws Exception + * if an error occurs. */ @Override public void write(File file) throws Exception { @@ -331,30 +334,25 @@ public void write(File file) throws Exception { File outputFile = getStoreLocation(); if (outputFile != null) { /* - * The uploaded file is being stored on disk - * in a temporary location so move it to the - * desired file. + * The uploaded file is being stored on disk in a temporary location so move it to the desired file. */ if (!outputFile.renameTo(file)) { FileUtils.copyFile(outputFile, file); } } else { /* - * For whatever reason we cannot write the - * file to disk. + * For whatever reason we cannot write the file to disk. */ - throw new FileUploadException( - "Cannot write uploaded file to disk!"); + throw new FileUploadException("Cannot write uploaded file to disk!"); } } } /** - * Deletes the underlying storage for a file item, including deleting any - * associated temporary disk file. Although this storage will be deleted - * automatically when the FileItem instance is garbage - * collected, this method can be used to ensure that this is done at an - * earlier time, thus preserving system resources. + * Deletes the underlying storage for a file item, including deleting any associated temporary disk file. + * Although this storage will be deleted automatically when the FileItem instance is garbage + * collected, this method can be used to ensure that this is done at an earlier time, thus preserving system + * resources. */ @Override public void delete() { @@ -366,8 +364,7 @@ public void delete() { } /** - * Returns the name of the field in the multipart form corresponding to - * this file item. + * Returns the name of the field in the multipart form corresponding to this file item. * * @return The name of the form field. * @see #setFieldName(java.lang.String) @@ -380,7 +377,8 @@ public String getFieldName() { /** * Sets the field name used to reference this file item. * - * @param fieldName The name of the form field. + * @param fieldName + * The name of the form field. * @see #getFieldName() */ @Override @@ -389,11 +387,10 @@ public void setFieldName(String fieldName) { } /** - * Determines whether or not a FileItem instance represents - * a simple form field. + * Determines whether or not a FileItem instance represents a simple form field. * - * @return true if the instance represents a simple form - * field; false if it represents an uploaded file. + * @return true if the instance represents a simple form field; false if it represents + * an uploaded file. * @see #setFormField(boolean) */ @Override @@ -402,11 +399,11 @@ public boolean isFormField() { } /** - * Specifies whether or not a FileItem instance represents - * a simple form field. + * Specifies whether or not a FileItem instance represents a simple form field. * - * @param state true if the instance represents a simple form - * field; false if it represents an uploaded file. + * @param state + * true if the instance represents a simple form field; false if it + * represents an uploaded file. * @see #isFormField() */ @Override @@ -415,12 +412,11 @@ public void setFormField(boolean state) { } /** - * Returns an {@link java.io.OutputStream OutputStream} that can - * be used for storing the contents of the file. + * Returns an {@link java.io.OutputStream OutputStream} that can be used for storing the contents of the file. * - * @return An {@link java.io.OutputStream OutputStream} that can be used - * for storing the contents of the file. - * @throws IOException if an error occurs. + * @return An {@link java.io.OutputStream OutputStream} that can be used for storing the contents of the file. + * @throws IOException + * if an error occurs. */ @Override public OutputStream getOutputStream() throws IOException { @@ -436,17 +432,13 @@ public OutputStream getOutputStream() throws IOException { // --------------------------------------------------------- Public methods /** - * Returns the {@link java.io.File} object for the FileItem's - * data's temporary location on the disk. Note that for - * FileItems that have their data stored in memory, - * this method will return null. When handling large - * files, you can use {@link java.io.File#renameTo(java.io.File)} to - * move the file to new location without copying the data, if the - * source and destination locations reside within the same logical - * volume. + * Returns the {@link java.io.File} object for the FileItem's data's temporary location on the + * disk. Note that for FileItems that have their data stored in memory, this method will return + * null. When handling large files, you can use {@link java.io.File#renameTo(java.io.File)} to move + * the file to new location without copying the data, if the source and destination locations reside within the + * same logical volume. * - * @return The data file, or null if the data is stored in - * memory. + * @return The data file, or null if the data is stored in memory. */ public File getStoreLocation() { return dfos.getFile(); @@ -454,10 +446,9 @@ public File getStoreLocation() { // ------------------------------------------------------ Protected methods /** - * Creates and returns a {@link java.io.File File} representing a uniquely - * named temporary file in the configured repository path. The lifetime of - * the file is tied to the lifetime of the FileItem instance; - * the file will be deleted when the instance is garbage collected. + * Creates and returns a {@link java.io.File File} representing a uniquely named temporary file in the + * configured repository path. The lifetime of the file is tied to the lifetime of the FileItem + * instance; the file will be deleted when the instance is garbage collected. * * @return The {@link java.io.File File} to be used for temporary storage. */ @@ -476,8 +467,8 @@ protected File getTempFile() { // -------------------------------------------------------- Private methods /** - * Returns an identifier that is unique within the class loader used to - * load this class, but does not have random-like apearance. + * Returns an identifier that is unique within the class loader used to load this class, but does not have + * random-like apearance. * * @return A String with the non-random looking instance identifier. */ @@ -496,12 +487,14 @@ private static String getUniqueId() { return id; } + @Override public String toString() { - return "name=" + this.getName() + ", StoreLocation=" + String.valueOf(this.getStoreLocation()) + ", size=" + this.getSize() + "bytes, " + "isFormField=" + isFormField() + ", FieldName=" + this.getFieldName(); + return "name=" + this.getName() + ", StoreLocation=" + String.valueOf(this.getStoreLocation()) + ", size=" + this.getSize() + + "bytes, " + "isFormField=" + isFormField() + ", FieldName=" + this.getFieldName(); } /** - * Returns the file item headers. + * Returns the file item headers. * * @return The file items headers. */ @@ -518,7 +511,7 @@ public FileItemHeaders getHeaders() { */ @Override public void setHeaders(FileItemHeaders pHeaders) { - headers = pHeaders; + headers = pHeaders; } } @@ -526,7 +519,8 @@ public void setHeaders(FileItemHeaders pHeaders) { public Map parse(InputStream body) { Map result = new HashMap<>(); try { - FileItemIteratorImpl iter = new FileItemIteratorImpl(body, Request.current().headers.get("content-type").value(), Request.current().encoding); + FileItemIteratorImpl iter = new FileItemIteratorImpl(body, Request.current().headers.get("content-type").value(), + Request.current().encoding); while (iter.hasNext()) { FileItemStream item = iter.next(); FileItem fileItem = new AutoFileItem(item); @@ -542,16 +536,17 @@ public Map parse(InputStream body) { // must resolve encoding String _encoding = Request.current().encoding; // this is our default String _contentType = fileItem.getContentType(); - if( _contentType != null ) { + if (_contentType != null) { HTTP.ContentTypeWithEncoding contentTypeEncoding = HTTP.parseContentType(_contentType); - if( contentTypeEncoding.encoding != null ) { + if (contentTypeEncoding.encoding != null) { _encoding = contentTypeEncoding.encoding; } } - putMapEntry(result, fileItem.getFieldName(), fileItem.getString( _encoding )); + putMapEntry(result, fileItem.getFieldName(), fileItem.getString(_encoding)); } else { - @SuppressWarnings("unchecked") List uploads = (List) Request.current().args.get("__UPLOADS"); + @SuppressWarnings("unchecked") + List uploads = (List) Request.current().args.get("__UPLOADS"); if (uploads == null) { uploads = new ArrayList<>(); Request.current().args.put("__UPLOADS", uploads); @@ -564,8 +559,7 @@ public Map parse(InputStream body) { } putMapEntry(result, fileItem.getFieldName(), fileItem.getFieldName()); } - } - finally { + } finally { fileItem.delete(); } } @@ -577,8 +571,9 @@ public Map parse(InputStream body) { throw new UnexpectedException(e); } return result; - } // ---------------------------------------------------------- Class methods - // ----------------------------------------------------- Manifest constants + } // ---------------------------------------------------------- Class methods + // ----------------------------------------------------- Manifest constants + /** * HTTP content type header name. */ @@ -609,13 +604,13 @@ public Map parse(InputStream body) { private static final String MULTIPART_MIXED = "multipart/mixed"; // ----------------------------------------------------------- Data members /** - * The maximum size permitted for the complete request, as opposed to - * {@link #fileSizeMax}. A value of -1 indicates no maximum. + * The maximum size permitted for the complete request, as opposed to {@link #fileSizeMax}. A value of -1 indicates + * no maximum. */ private long sizeMax = -1; /** - * The maximum size permitted for a single uploaded file, as opposed to - * {@link #sizeMax}. A value of -1 indicates no maximum. + * The maximum size permitted for a single uploaded file, as opposed to {@link #sizeMax}. A value of -1 indicates no + * maximum. */ private long fileSizeMax = -1; @@ -624,8 +619,8 @@ public Map parse(InputStream body) { /** * Retrieves the boundary from the Content-type header. * - * @param contentType The value of the content type header from which to extract the - * boundary value. + * @param contentType + * The value of the content type header from which to extract the boundary value. * @return The boundary, as a byte array. */ private byte[] getBoundary(String contentType) { @@ -634,7 +629,7 @@ private byte[] getBoundary(String contentType) { parser.setLowerCaseNames(true); // Parameter parser can handle null input Map params = parser.parse(contentType, ';'); - String boundaryStr = (String) params.get("boundary"); + String boundaryStr = params.get("boundary"); if (boundaryStr == null) { return null; @@ -649,10 +644,10 @@ private byte[] getBoundary(String contentType) { } /** - * Retrieves the file name from the Content-disposition - * header. + * Retrieves the file name from the Content-disposition header. * - * @param headers A Map containing the HTTP request headers. + * @param headers + * A Map containing the HTTP request headers. * @return The file name for the current encapsulation. */ private String getFileName(Map headers) { @@ -687,17 +682,16 @@ private String getFileName(Map headers) { } /** - * Retrieves the field name from the Content-disposition - * header. + * Retrieves the field name from the Content-disposition header. * - * @param headers A Map containing the HTTP request headers. + * @param headers + * A Map containing the HTTP request headers. * @return The field name for the current encapsulation. */ private String getFieldName(Map headers) { String fieldName = null; String cd = getHeader(headers, CONTENT_DISPOSITION); - if (cd != null && (cd.toLowerCase().startsWith(FORM_DATA) || - cd.toLowerCase().startsWith(ATTACHMENT))) { + if (cd != null && (cd.toLowerCase().startsWith(FORM_DATA) || cd.toLowerCase().startsWith(ATTACHMENT))) { ParameterParser parser = new ParameterParser(); parser.setLowerCaseNames(true); @@ -716,18 +710,18 @@ private String getFieldName(Map headers) { * Parses the header-part and returns as key/value pairs. *

*

- * If there are multiple headers of the same names, the name will map to a - * comma-separated list containing the values. + * If there are multiple headers of the same names, the name will map to a comma-separated list containing the + * values. * - * @param headerPart The header-part of the current - * encapsulation. + * @param headerPart + * The header-part of the current encapsulation. * @return A Map containing the parsed HTTP request headers. */ private Map parseHeaders(String headerPart) { int len = headerPart.length(); Map headers = new HashMap<>(); int start = 0; - for (; ;) { + for (;;) { int end = parseEndOfLine(headerPart, start); if (start == end) { break; @@ -759,13 +753,15 @@ private Map parseHeaders(String headerPart) { /** * Skips bytes until the end of the current line. * - * @param headerPart The headers, which are being parsed. - * @param end Index of the last byte, which has yet been processed. + * @param headerPart + * The headers, which are being parsed. + * @param end + * Index of the last byte, which has yet been processed. * @return Index of the \r\n sequence, which indicates end of line. */ private int parseEndOfLine(String headerPart, int end) { int index = end; - for (; ;) { + for (;;) { int offset = headerPart.indexOf('\r', index); if (offset == -1 || offset + 1 >= headerPart.length()) { throw new IllegalStateException("Expected headers to be terminated by an empty line."); @@ -780,8 +776,10 @@ private int parseEndOfLine(String headerPart, int end) { /** * Reads the next header line. * - * @param headers String with all headers. - * @param header Map where to store the current header. + * @param headers + * String with all headers. + * @param header + * Map where to store the current header. */ private void parseHeaderLine(Map headers, String header) { int colonOffset = header.indexOf(':'); @@ -801,21 +799,20 @@ private void parseHeaderLine(Map headers, String header) { } /** - * Returns the header with the specified name from the supplied map. The - * header lookup is case-insensitive. + * Returns the header with the specified name from the supplied map. The header lookup is case-insensitive. * - * @param headers A Map containing the HTTP request headers. - * @param name The name of the header to return. - * @return The value of specified header, or a comma-separated list if there - * were multiple headers of that name. + * @param headers + * A Map containing the HTTP request headers. + * @param name + * The name of the header to return. + * @return The value of specified header, or a comma-separated list if there were multiple headers of that name. */ private String getHeader(Map headers, String name) { return headers.get(name.toLowerCase()); } /** - * The iterator, which is returned by - * {@link FileUploadBase#getItemIterator(RequestContext)}. + * The iterator, which is returned by {@link FileUploadBase#getItemIterator(RequestContext)}. */ private class FileItemIteratorImpl implements FileItemIterator { @@ -854,10 +851,14 @@ private class FileItemStreamImpl implements FileItemStream { /** * CReates a new instance. * - * @param pName The items file name, or null. - * @param pFieldName The items field name. - * @param pContentType The items content type, or null. - * @param pFormField Whether the item is a form field. + * @param pName + * The items file name, or null. + * @param pFieldName + * The items field name. + * @param pContentType + * The items content type, or null. + * @param pFormField + * Whether the item is a form field. */ FileItemStreamImpl(String pName, String pFieldName, String pContentType, boolean pFormField) { name = pName; @@ -870,7 +871,9 @@ private class FileItemStreamImpl implements FileItemStream { @Override protected void raiseError(long pSizeMax, long pCount) throws IOException { - FileUploadException e = new FileSizeLimitExceededException("The field " + fieldName + " exceeds its maximum permitted " + " size of " + pSizeMax + " characters.", pCount, pSizeMax); + FileUploadException e = new FileSizeLimitExceededException( + "The field " + fieldName + " exceeds its maximum permitted " + " size of " + pSizeMax + " characters.", + pCount, pSizeMax); throw new FileUploadIOException(e); } }; @@ -888,7 +891,6 @@ public void setHeaders(FileItemHeaders fileItemHeaders) { this.fileItemHeaders = fileItemHeaders; } - /** * Returns the items content type, or null. * @@ -930,11 +932,11 @@ public boolean isFormField() { } /** - * Returns an input stream, which may be used to read the items - * contents. + * Returns an input stream, which may be used to read the items contents. * * @return Opened input stream. - * @throws IOException An I/O error occurred. + * @throws IOException + * An I/O error occurred. */ @Override public InputStream openStream() throws IOException { @@ -950,7 +952,8 @@ public InputStream openStream() throws IOException { /** * Closes the file item. * - * @throws IOException An I/O error occurred. + * @throws IOException + * An I/O error occurred. */ void close() throws IOException { stream.close(); @@ -989,13 +992,16 @@ void close() throws IOException { /** * Creates a new instance. * - * @throws FileUploadException An error occurred while parsing the request. - * @throws IOException An I/O error occurred. + * @throws FileUploadException + * An error occurred while parsing the request. + * @throws IOException + * An I/O error occurred. */ FileItemIteratorImpl(InputStream input, String contentType, String charEncoding) throws FileUploadException, IOException { if ((null == contentType) || (!contentType.toLowerCase().startsWith(MULTIPART))) { - throw new InvalidContentTypeException("the request doesn't contain a " + MULTIPART_FORM_DATA + " or " + MULTIPART_MIXED + " stream, content type header is " + contentType); + throw new InvalidContentTypeException("the request doesn't contain a " + MULTIPART_FORM_DATA + " or " + MULTIPART_MIXED + + " stream, content type header is " + contentType); } if (sizeMax >= 0) { @@ -1005,7 +1011,8 @@ void close() throws IOException { @Override protected void raiseError(long pSizeMax, long pCount) throws IOException { - FileUploadException ex = new SizeLimitExceededException("the request was rejected because" + " its size (" + pCount + ") exceeds the configured maximum" + " (" + pSizeMax + ")", pCount, pSizeMax); + FileUploadException ex = new SizeLimitExceededException("the request was rejected because" + " its size (" + pCount + + ") exceeds the configured maximum" + " (" + pSizeMax + ")", pCount, pSizeMax); throw new FileUploadIOException(ex); } }; @@ -1028,7 +1035,8 @@ protected void raiseError(long pSizeMax, long pCount) throws IOException { * Called for finding the nex item, if any. * * @return True, if an next item was found, otherwise false. - * @throws IOException An I/O error occurred. + * @throws IOException + * An I/O error occurred. */ private boolean findNextItem() throws IOException { if (eof) { @@ -1038,7 +1046,7 @@ private boolean findNextItem() throws IOException { currentItem.close(); currentItem = null; } - for (; ;) { + for (;;) { boolean nextPart; if (skipPreamble) { nextPart = multi.skipPreamble(); @@ -1089,13 +1097,13 @@ private boolean findNextItem() throws IOException { } /** - * Returns, whether another instance of {@link FileItemStream} is - * available. + * Returns, whether another instance of {@link FileItemStream} is available. * - * @return True, if one or more additional file items are available, - * otherwise false. - * @throws FileUploadException Parsing or processing the file item failed. - * @throws IOException Reading the file item failed. + * @return True, if one or more additional file items are available, otherwise false. + * @throws FileUploadException + * Parsing or processing the file item failed. + * @throws IOException + * Reading the file item failed. */ @Override public boolean hasNext() throws FileUploadException, IOException { @@ -1111,13 +1119,13 @@ public boolean hasNext() throws FileUploadException, IOException { /** * Returns the next available {@link FileItemStream}. * - * @return FileItemStream instance, which provides access to the next - * file item. + * @return FileItemStream instance, which provides access to the next file item. * @throws java.util.NoSuchElementException - * No more items are available. Use {@link #hasNext()} to - * prevent this exception. - * @throws FileUploadException Parsing or processing the file item failed. - * @throws IOException Reading the file item failed. + * No more items are available. Use {@link #hasNext()} to prevent this exception. + * @throws FileUploadException + * Parsing or processing the file item failed. + * @throws IOException + * Reading the file item failed. */ @Override public FileItemStream next() throws FileUploadException, IOException { @@ -1130,8 +1138,7 @@ public FileItemStream next() throws FileUploadException, IOException { } /** - * This exception is thrown for hiding an inner {@link FileUploadException} - * in an {@link IOException}. + * This exception is thrown for hiding an inner {@link FileUploadException} in an {@link IOException}. */ private static class FileUploadIOException extends IOException { @@ -1140,15 +1147,15 @@ private static class FileUploadIOException extends IOException { */ private static final long serialVersionUID = -7047616958165584154L; /** - * The exceptions cause; we overwrite the parent classes field, which is - * available since Java 1.4 only. + * The exceptions cause; we overwrite the parent classes field, which is available since Java 1.4 only. */ private final FileUploadException cause; /** * Creates a FileUploadIOException with the given cause. * - * @param pCause The exceptions cause, if any, or null. + * @param pCause + * The exceptions cause, if any, or null. */ public FileUploadIOException(FileUploadException pCause) { // We're not doing super(pCause) cause of 1.3 compatibility. @@ -1177,10 +1184,10 @@ private static class InvalidContentTypeException extends FileUploadException { private static final long serialVersionUID = -9073026332015646668L; /** - * Constructs an InvalidContentTypeException with the - * specified detail message. + * Constructs an InvalidContentTypeException with the specified detail message. * - * @param message The detail message. + * @param message + * The detail message. */ public InvalidContentTypeException(String message) { super(message); @@ -1197,16 +1204,17 @@ private static class IOFileUploadException extends FileUploadException { */ private static final long serialVersionUID = 1749796615868477269L; /** - * The exceptions cause; we overwrite the parent classes field, which is - * available since Java 1.4 only. + * The exceptions cause; we overwrite the parent classes field, which is available since Java 1.4 only. */ private final IOException cause; /** * Creates a new instance with the given cause. * - * @param pMsg The detail message. - * @param pException The exceptions cause. + * @param pMsg + * The detail message. + * @param pException + * The exceptions cause. */ public IOFileUploadException(String pMsg, IOException pException) { super(pMsg); @@ -1241,9 +1249,12 @@ protected abstract static class SizeException extends FileUploadException { /** * Creates a new instance. * - * @param message The detail message. - * @param actual The actual number of bytes in the request. - * @param permitted The requests size limit, in bytes. + * @param message + * The detail message. + * @param actual + * The actual number of bytes in the request. + * @param permitted + * The requests size limit, in bytes. */ protected SizeException(String message, long actual, long permitted) { super(message); @@ -1281,12 +1292,15 @@ private static class SizeLimitExceededException extends SizeException { private static final long serialVersionUID = -2474893167098052828L; /** - * Constructs a SizeExceededException with the specified - * detail message, and actual and permitted sizes. + * Constructs a SizeExceededException with the specified detail message, and actual and permitted + * sizes. * - * @param message The detail message. - * @param actual The actual request size. - * @param permitted The maximum permitted request size. + * @param message + * The detail message. + * @param actual + * The actual request size. + * @param permitted + * The maximum permitted request size. */ public SizeLimitExceededException(String message, long actual, long permitted) { super(message, actual, permitted); @@ -1304,12 +1318,15 @@ private static class FileSizeLimitExceededException extends SizeException { private static final long serialVersionUID = 8150776562029630058L; /** - * Constructs a SizeExceededException with the specified - * detail message, and actual and permitted sizes. + * Constructs a SizeExceededException with the specified detail message, and actual and permitted + * sizes. * - * @param message The detail message. - * @param actual The actual request size. - * @param permitted The maximum permitted request size. + * @param message + * The detail message. + * @param actual + * The actual request size. + * @param permitted + * The maximum permitted request size. */ public FileSizeLimitExceededException(String message, long actual, long permitted) { super(message, actual, permitted); diff --git a/framework/src/play/data/validation/Equals.java b/framework/src/play/data/validation/Equals.java index 24e112269f..f0b9d228ce 100644 --- a/framework/src/play/data/validation/Equals.java +++ b/framework/src/play/data/validation/Equals.java @@ -4,24 +4,23 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; + import net.sf.oval.configuration.annotation.Constraint; /** - * This field must be equals to another field. - * Message key: validation.equals - * $1: field name - * $2: other field name + * This field must be equals to another field. Message key: validation.equals $1: field name $2: other field name */ @Retention(RetentionPolicy.RUNTIME) -@Target({ElementType.FIELD, ElementType.PARAMETER}) +@Target({ ElementType.FIELD, ElementType.PARAMETER }) @Constraint(checkWith = EqualsCheck.class) public @interface Equals { String message() default EqualsCheck.mes; - + /** * The other field name + * + * @return The other field name */ String value(); } - diff --git a/framework/src/play/db/Configuration.java b/framework/src/play/db/Configuration.java index a691a6b0fe..ffb2a6f8e3 100644 --- a/framework/src/play/db/Configuration.java +++ b/framework/src/play/db/Configuration.java @@ -1,80 +1,88 @@ package play.db; -import java.util.*; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.Set; +import java.util.TreeSet; -import play.*; import jregex.Matcher; import jregex.Pattern; +import play.Play; public class Configuration { - + public String configName; - - - public boolean isDefault(){ + + public boolean isDefault() { return DB.DEFAULT.equals(this.configName); } - - public Configuration(String configurationName){ + + public Configuration(String configurationName) { this.configName = configurationName; } - - - public static Set getDbNames() { - TreeSet dbNames = new TreeSet<>(); - // search for case db= or db.url= as at least one of these property is required - String DB_CONFIG_PATTERN = "^db\\.([^\\.]*)$|^db\\.([^\\.]*)\\.url$"; - Pattern pattern = new jregex.Pattern(DB_CONFIG_PATTERN); - - // List of properties with 2 words - List dbProperties = Arrays.asList("db.driver", "db.url", "db.user", "db.pass", "db.isolation", "db.destroyMethod", "db.testquery"); - - for (String property : Play.configuration.stringPropertyNames()) { - Matcher m = pattern.matcher(property); - if (m.matches() && !dbProperties.contains(property)) { - String dbName = (m.group(1) != null ? m.group(1) : m.group(2)); - dbNames.add(dbName); - } - // Special case db=... and - if ("db".equals(property) || "db.url".equals(property)) { - dbNames.add("default"); - } - } - return new TreeSet<>(dbNames); - } - - public String getProperty(String key) { - return this.getProperty(key, null); - } - - - public String getProperty(String key, String defaultString) { - if (key != null) { - String newKey = generateKey(key); - Object value = Play.configuration.get(newKey); - if (value == null && this.isDefault()){ - value = Play.configuration.get(key); - } - if (value != null){ - return value.toString(); - } - } - - return defaultString; - } - - /** - * - * @param key - * @param value - * @return the previous value of the specified key in this hashtable, or null if it did not have one - */ - public Object put(String key, String value) { - if (key != null) { - return Play.configuration.put(generateKey(key), value); - } - return null; - } + + public static Set getDbNames() { + TreeSet dbNames = new TreeSet<>(); + // search for case db= or db.url= as at least one of these property is required + String DB_CONFIG_PATTERN = "^db\\.([^\\.]*)$|^db\\.([^\\.]*)\\.url$"; + Pattern pattern = new jregex.Pattern(DB_CONFIG_PATTERN); + + // List of properties with 2 words + List dbProperties = Arrays.asList("db.driver", "db.url", "db.user", "db.pass", "db.isolation", "db.destroyMethod", + "db.testquery"); + + for (String property : Play.configuration.stringPropertyNames()) { + Matcher m = pattern.matcher(property); + if (m.matches() && !dbProperties.contains(property)) { + String dbName = (m.group(1) != null ? m.group(1) : m.group(2)); + dbNames.add(dbName); + } + // Special case db=... and + if ("db".equals(property) || "db.url".equals(property)) { + dbNames.add("default"); + } + } + return new TreeSet<>(dbNames); + } + + public String getProperty(String key) { + return this.getProperty(key, null); + } + + public String getProperty(String key, String defaultString) { + if (key != null) { + String newKey = generateKey(key); + Object value = Play.configuration.get(newKey); + if (value == null && this.isDefault()) { + value = Play.configuration.get(key); + } + if (value != null) { + return value.toString(); + } + } + + return defaultString; + } + + /** + * Add a parameter in the configuration + * + * @param key + * the key of the parameter + * @param value + * the value of the parameter + * @return the previous value of the specified key in this hashtable, or null if it did not have one + */ + public Object put(String key, String value) { + if (key != null) { + return Play.configuration.put(generateKey(key), value); + } + return null; + } String generateKey(String key) { Pattern pattern = new Pattern("^(db|jpa|hibernate){1}(\\.?[\\da-zA-Z\\.-_]*)$"); @@ -85,36 +93,35 @@ String generateKey(String key) { return key; } - public Map getProperties() { Map properties = new HashMap<>(); Properties props = Play.configuration; - + for (Object key : Collections.list(props.keys())) { String keyName = key.toString(); - if (keyName.startsWith("db") || keyName.startsWith("hibernate") ) { - if (keyName.startsWith("db." + this.configName) || keyName.startsWith("hibernate." + this.configName) ) { + if (keyName.startsWith("db") || keyName.startsWith("hibernate")) { + if (keyName.startsWith("db." + this.configName) || keyName.startsWith("hibernate." + this.configName)) { String type = keyName.substring(0, keyName.indexOf('.')); String newKey = type; - if(keyName.length() > (type + "." + this.configName).length()){ - newKey += "." + keyName.substring((type + "." + this.configName).length() + 1); + if (keyName.length() > (type + "." + this.configName).length()) { + newKey += "." + keyName.substring((type + "." + this.configName).length() + 1); } properties.put(newKey, props.get(key).toString()); - }else if(this.isDefault()){ - boolean isDefaultProperty = true; + } else if (this.isDefault()) { + boolean isDefaultProperty = true; Set dBNames = Configuration.getDbNames(); - for(String dbName : dBNames){ - if(key.toString().startsWith("db." + dbName) || key.toString().startsWith("hibernate." + dbName)){ + for (String dbName : dBNames) { + if (key.toString().startsWith("db." + dbName) || key.toString().startsWith("hibernate." + dbName)) { isDefaultProperty = false; break; } } - if(isDefaultProperty){ + if (isDefaultProperty) { properties.put(key.toString(), props.get(key).toString()); } } } - } + } return properties; } } diff --git a/framework/src/play/db/DB.java b/framework/src/play/db/DB.java index 4f49c15d63..ce043bcf6c 100644 --- a/framework/src/play/db/DB.java +++ b/framework/src/play/db/DB.java @@ -9,6 +9,7 @@ import java.util.HashSet; import java.util.Map; import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; import javax.sql.DataSource; import javax.sql.RowSet; @@ -18,11 +19,9 @@ import com.sun.rowset.CachedRowSetImpl; +import play.Logger; import play.db.jpa.JPA; import play.exceptions.DatabaseException; -import play.Logger; - -import java.util.concurrent.ConcurrentHashMap; /** * Database connection utilities. @@ -31,6 +30,7 @@ public class DB { /** * The loaded datasource. + * * @see ExtendedDatasource */ protected static final Map datasources = new ConcurrentHashMap<>(); @@ -147,6 +147,9 @@ public static void close() { /** * Close an given open connections for the current thread + * + * @param name + * Name of the DB */ public static void close(String name) { Map map = localConnection.get(); @@ -158,8 +161,7 @@ public static void close(String name) { try { connection.close(); } catch (Exception e) { - throw new DatabaseException("It's possible than the connection '" + name - + "'was not properly closed !", e); + throw new DatabaseException("It's possible than the connection '" + name + "'was not properly closed !", e); } } } @@ -168,6 +170,8 @@ public static void close(String name) { /** * Open a connection for the current thread. * + * @param name + * Name of the DB * @return A valid SQL connection */ public static Connection getConnection(String name) { @@ -202,10 +206,13 @@ public static Connection getConnection() { /** * Execute an SQL update - * + * + * @param name + * the DB name * @param SQL - * @return true if the next result is a ResultSet object; false if it is an - * update count or there are no more results + * the SQL statement + * @return true if the next result is a ResultSet object; false if it is an update count or there are no more + * results */ public static boolean execute(String name, String SQL) { Statement statement = null; @@ -222,10 +229,25 @@ public static boolean execute(String name, String SQL) { return false; } + /** + * Execute an SQL update + * + * @param SQL + * the SQL statement + * @return true if the next result is a ResultSet object; false if it is an update count or there are no more + * results + */ public static boolean execute(String SQL) { return execute(DEFAULT, SQL); } + /** + * Execute an SQL query + * + * @param SQL + * the SQL statement + * @return The ResultSet object; false if it is an update count or there are no more results + */ public static RowSet executeQuery(String SQL) { return executeQuery(DEFAULT, SQL); } @@ -233,7 +255,10 @@ public static RowSet executeQuery(String SQL) { /** * Execute an SQL query * + * @param name + * the DB name * @param SQL + * the SQL statement * @return The rowSet of the query */ public static RowSet executeQuery(String name, String SQL) { @@ -281,13 +306,15 @@ public static void safeCloseStatement(Statement statement) { /** * Destroy the datasource + * + * @param name + * the DB name */ public static void destroy(String name) { try { ExtendedDatasource extDatasource = datasources.get(name); if (extDatasource != null && extDatasource.getDestroyMethod() != null) { - Method close = extDatasource.datasource.getClass().getMethod(extDatasource.getDestroyMethod(), - new Class[] {}); + Method close = extDatasource.datasource.getClass().getMethod(extDatasource.getDestroyMethod(), new Class[] {}); if (close != null) { close.invoke(extDatasource.getDataSource(), new Object[] {}); datasources.remove(name); diff --git a/framework/src/play/db/Evolutions.java b/framework/src/play/db/Evolutions.java index e7d082a55e..94256f2605 100644 --- a/framework/src/play/db/Evolutions.java +++ b/framework/src/play/db/Evolutions.java @@ -6,7 +6,6 @@ import java.sql.SQLException; import java.util.ArrayList; import java.util.Collections; -import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -151,11 +150,11 @@ public static void main(String[] args) throws SQLException { * Method to handle the "default" action * * @param dbName - * : database name + * database name * @param moduleRoot - * : the module root of evolutions + * the module root of evolutions * @param evolutions - * : list of evolutions + * list of evolutions */ private static void handleDefaultAction(String dbName, Entry moduleRoot, List evolutions) { System.out.println("~ Your database " + dbName + " needs evolutions for " + moduleRoot.getKey() + "!"); @@ -175,9 +174,9 @@ private static void handleDefaultAction(String dbName, Entry moduleRoot) { @@ -202,11 +201,11 @@ private static boolean handleResolveAction(String dbName, Entry moduleRoot, List evolutions) { @@ -235,11 +234,11 @@ private static boolean handleApplyAction(String dbName, Entry moduleRoot, List evolutions) { @@ -387,8 +386,7 @@ public void onApplicationStart() { } /** - * Checks if evolutions is disabled in application.conf (property - * "evolutions.enabled") + * Checks if evolutions is disabled in application.conf (property "evolutions.enabled") */ private boolean isDisabled() { return "false".equals(Play.configuration.getProperty("evolutions.enabled", "true")); @@ -578,7 +576,7 @@ public static synchronized List getEvolutionScript(String dbName, Str } public static synchronized Stack listApplicationEvolutions(String dBName, String moduleKey, - VirtualFile evolutionsDirectory) { + VirtualFile evolutionsDirectory) { Stack evolutions = new Stack<>(); evolutions.add(new Evolution("", 0, "", "", true)); if (evolutionsDirectory.exists()) { diff --git a/framework/src/play/db/SQLSplitter.java b/framework/src/play/db/SQLSplitter.java index 946413cc4d..dd1117a71f 100644 --- a/framework/src/play/db/SQLSplitter.java +++ b/framework/src/play/db/SQLSplitter.java @@ -1,58 +1,64 @@ package play.db; -import java.util.*; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.NoSuchElementException; public class SQLSplitter implements Iterable { /** * Skips the index past the quote. * - * @param s The string - * @param start The starting character of the quote. - * @return The index that skips past the quote starting at start. If the quote does not start at that point, it simply returns start. + * @param s + * The string + * @param start + * The starting character of the quote. + * @return The index that skips past the quote starting at start. If the quote does not start at that point, it + * simply returns start. */ static int consumeQuote(CharSequence s, int start) { - if (start >= s.length()) return start; + if (start >= s.length()) + return start; char ender; switch (s.charAt(start)) { - case '\'': - ender = '\''; - break; - case '"': - ender = '"'; - break; - case '[': - ender = ']'; - break; - - case '`': - ender = '`'; - break; - case '$': { - int quoteEnd = start + 1; - for (; s.charAt(quoteEnd) != '$'; ++quoteEnd) - if (quoteEnd >= s.length()) - return quoteEnd; - int i = quoteEnd + 1; - while (i < s.length()) { - if (s.charAt(i) == '$') { - boolean match = true; - for (int j = start; j <= quoteEnd && i < s.length(); ++j, ++i) { - if (s.charAt(i) != s.charAt(j)) { - match = false; - break; - } + case '\'': + ender = '\''; + break; + case '"': + ender = '"'; + break; + case '[': + ender = ']'; + break; + + case '`': + ender = '`'; + break; + case '$': { + int quoteEnd = start + 1; + for (; s.charAt(quoteEnd) != '$'; ++quoteEnd) + if (quoteEnd >= s.length()) + return quoteEnd; + int i = quoteEnd + 1; + while (i < s.length()) { + if (s.charAt(i) == '$') { + boolean match = true; + for (int j = start; j <= quoteEnd && i < s.length(); ++j, ++i) { + if (s.charAt(i) != s.charAt(j)) { + match = false; + break; } - if (match) - return i; - } else - ++i; - } - return i; + } + if (match) + return i; + } else + ++i; } + return i; + } - default: - return start; + default: + return start; } boolean escaped = false; @@ -95,66 +101,72 @@ static boolean isNext(CharSequence s, int start, char c) { /** * Skips the index past the comment. * - * @param s The string - * @param start The starting character of the comment - * @return The index that skips past the comment starting at start. If the comment does not start at that point, it simply returns start. + * @param s + * The string + * @param start + * The starting character of the comment + * @return The index that skips past the comment starting at start. If the comment does not start at that point, it + * simply returns start. */ static int consumeComment(CharSequence s, int start) { - if (start >= s.length()) return start; + if (start >= s.length()) + return start; switch (s.charAt(start)) { - case '-': - if (isNext(s, start, '-')) - return consumeTillNextLine(s, start + 2); - else - return start; - - case '#': - return consumeTillNextLine(s, start); - - case '/': - if (isNext(s, start, '*')) { - start += 2; - while (start < s.length()) { - if (s.charAt(start) == '*') { - ++start; - if (start < s.length() && s.charAt(start) == '/') - return start + 1; - } else - ++start; - } - } + case '-': + if (isNext(s, start, '-')) + return consumeTillNextLine(s, start + 2); + else return start; - case '{': - while (start < s.length() && s.charAt(start) != '}') - ++start; - return start + 1; + case '#': + return consumeTillNextLine(s, start); - default: - return start; + case '/': + if (isNext(s, start, '*')) { + start += 2; + while (start < s.length()) { + if (s.charAt(start) == '*') { + ++start; + if (start < s.length() && s.charAt(start) == '/') + return start + 1; + } else + ++start; + } + } + return start; + + case '{': + while (start < s.length() && s.charAt(start) != '}') + ++start; + return start + 1; + + default: + return start; } } static int consumeParentheses(CharSequence s, int start) { - if (start >= s.length()) return start; + if (start >= s.length()) + return start; switch (s.charAt(start)) { - case '(': - ++start; - while (start < s.length()) { - if (s.charAt(start) == ')') - return start + 1; - start = nextChar(s, start); - } - break; - default: - break; + case '(': + ++start; + while (start < s.length()) { + if (s.charAt(start) == ')') + return start + 1; + start = nextChar(s, start); + } + break; + default: + break; } return start; } static int nextChar(CharSequence sql, int start) { int i = consumeParentheses(sql, consumeComment(sql, consumeQuote(sql, start))); - if (i == start) return Math.min(start + 1, sql.length()); + if (i == start) + return Math.min(start + 1, sql.length()); do { int j = consumeParentheses(sql, consumeComment(sql, consumeQuote(sql, i))); if (j == i) @@ -165,6 +177,10 @@ static int nextChar(CharSequence sql, int start) { /** * Splits the SQL "properly" based on semicolons. Respecting quotes and comments. + * + * @param sql + * the SQL statement + * @return List of all SQL statements */ public static ArrayList splitSQL(CharSequence sql) { ArrayList ret = new ArrayList<>(); diff --git a/framework/src/play/db/jpa/GenericModel.java b/framework/src/play/db/jpa/GenericModel.java index 1b7cebac20..f9031f9d4f 100644 --- a/framework/src/play/db/jpa/GenericModel.java +++ b/framework/src/play/db/jpa/GenericModel.java @@ -1,10 +1,30 @@ package play.db.jpa; +import java.lang.annotation.Annotation; +import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.ParameterizedType; -import java.util.*; - -import javax.persistence.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.SortedSet; +import java.util.TreeSet; + +import javax.persistence.ManyToMany; +import javax.persistence.ManyToOne; +import javax.persistence.MappedSuperclass; +import javax.persistence.NoResultException; +import javax.persistence.OneToMany; +import javax.persistence.OneToOne; +import javax.persistence.PostLoad; +import javax.persistence.PostPersist; +import javax.persistence.PostUpdate; +import javax.persistence.Query; import org.apache.commons.lang.StringUtils; @@ -17,27 +37,50 @@ import play.exceptions.UnexpectedException; import play.mvc.Scope.Params; -import java.lang.annotation.Annotation; -import java.lang.reflect.Constructor; - /** - * A super class for JPA entities + * A super class for JPA entities */ @MappedSuperclass @SuppressWarnings("unchecked") public class GenericModel extends JPABase { /** - * This method is deprecated. Use this instead: - * - * public static <T extends JPABase> T create(ParamNode rootParamNode, String name, Class<?> type, Annotation[] annotations) + * Create a new model + * + * @param type + * the class of the object + * @param name + * name of the object + * @param params + * parameters used to create the new object + * @param annotations + * annotations on the model + * @param + * The entity class + * @return The created entity + * @deprecated use method {{@link #create(ParamNode, String, Class, Annotation[]) }} */ @Deprecated public static T create(Class type, String name, Map params, Annotation[] annotations) { ParamNode rootParamNode = ParamNode.convert(params); - return (T)create(rootParamNode, name, type, annotations); + return (T) create(rootParamNode, name, type, annotations); } + /** + * Create a new model + * + * @param rootParamNode + * parameters used to create the new object + * @param name + * name of the object + * @param type + * the class of the object + * @param annotations + * annotations on the model + * @param + * The entity class + * @return The created entity + */ public static T create(ParamNode rootParamNode, String name, Class type, Annotation[] annotations) { try { Constructor c = type.getDeclaredConstructor(); @@ -50,24 +93,65 @@ public static T create(ParamNode rootParamNode, String name, } /** - * This method is deprecated. Use this instead: - * - * public static <T extends JPABase> T edit(ParamNode rootParamNode, String name, Object o, Annotation[] annotations) - * - * @see GenericModel#edit(ParamNode, String, Object, Annotation[]) + * Edit a model * + * @param o + * Object to edit + * @param name + * name of the object + * @param params + * list of parameters + * @param annotations + * annotations on the model + * @param + * class of the entity * @return the entity + * + * @see GenericModel#edit(ParamNode, String, Object, Annotation[]) + * @deprecated use method {{@link GenericModel#edit(ParamNode, String, Object, Annotation[]) }} */ @Deprecated public static T edit(Object o, String name, Map params, Annotation[] annotations) { ParamNode rootParamNode = ParamNode.convert(params); - return (T)edit( rootParamNode, name, o, annotations); + return (T) edit(rootParamNode, name, o, annotations); } + /** + * Edit a model + * + * @param rootParamNode + * parameters used to create the new object + * @param name + * name of the object + * @param o + * the entity to update + * @param annotations + * annotations on the model + * @param + * class of the entity + * @return the entity + */ public static T edit(ParamNode rootParamNode, String name, Object o, Annotation[] annotations) { return edit(JPA.DEFAULT, rootParamNode, name, o, annotations); } + /** + * Edit a model + * + * @param dbName + * the db name + * @param rootParamNode + * parameters used to create the new object + * @param name + * name of the object + * @param o + * the entity to update + * @param annotations + * annotations on the model + * @param + * class of the entity + * @return the entity + */ public static T edit(String dbName, ParamNode rootParamNode, String name, Object o, Annotation[] annotations) { // #1601 - If name is empty, we're dealing with "root" request parameters (without prefixes). // Must not call rootParamNode.getChild in that case, as it returns null. Use rootParamNode itself instead. @@ -88,15 +172,16 @@ public static T edit(String dbName, ParamNode rootParamNode, boolean isEntity = false; String relation = null; boolean multiple = false; - - // First try the field + + // First try the field Annotation[] fieldAnnotations = field.getAnnotations(); // and check with the profiles annotations - BindingAnnotations bindingAnnotations = new BindingAnnotations(fieldAnnotations, new BindingAnnotations(annotations).getProfiles()); + BindingAnnotations bindingAnnotations = new BindingAnnotations(fieldAnnotations, + new BindingAnnotations(annotations).getProfiles()); if (bindingAnnotations.checkNoBinding()) { continue; } - + if (field.isAnnotationPresent(OneToOne.class) || field.isAnnotationPresent(ManyToOne.class)) { isEntity = true; relation = field.getType().getName(); @@ -130,9 +215,10 @@ public static T edit(String dbName, ParamNode rootParamNode, if (_id == null || _id.equals("")) { continue; } - + Query q = JPA.em(dbName).createQuery("from " + relation + " where " + keyName + " = ?1"); - q.setParameter(1, Binder.directBind(rootParamNode.getOriginalKey(), annotations,_id, Model.Manager.factoryFor((Class) Play.classloader.loadClass(relation)).keyType(), null)); + q.setParameter(1, Binder.directBind(rootParamNode.getOriginalKey(), annotations, _id, + Model.Manager.factoryFor((Class) Play.classloader.loadClass(relation)).keyType(), null)); try { l.add(q.getSingleResult()); @@ -147,21 +233,22 @@ public static T edit(String dbName, ParamNode rootParamNode, if (ids != null && ids.length > 0 && !ids[0].equals("")) { Query q = JPA.em(dbName).createQuery("from " + relation + " where " + keyName + " = ?1"); - q.setParameter(1, Binder.directBind(rootParamNode.getOriginalKey(), annotations, ids[0], Model.Manager.factoryFor((Class) Play.classloader.loadClass(relation)).keyType(), null)); + q.setParameter(1, Binder.directBind(rootParamNode.getOriginalKey(), annotations, ids[0], + Model.Manager.factoryFor((Class) Play.classloader.loadClass(relation)).keyType(), null)); try { Object to = q.getSingleResult(); edit(paramNode, field.getName(), to, field.getAnnotations()); // Remove it to prevent us from finding it again later - paramNode.removeChild( field.getName(), removedNodesList); + paramNode.removeChild(field.getName(), removedNodesList); bw.set(field.getName(), o, to); } catch (NoResultException e) { Validation.addError(fieldParamNode.getOriginalKey(), "validation.notFound", ids[0]); // Remove only the key to prevent us from finding it again later // This how the old impl does it.. fieldParamNode.removeChild(keyName, removedNodesList); - if (fieldParamNode.getAllChildren().size()==0) { + if (fieldParamNode.getAllChildren().size() == 0) { // remove the whole node.. - paramNode.removeChild( field.getName(), removedNodesList); + paramNode.removeChild(field.getName(), removedNodesList); } } @@ -184,32 +271,68 @@ public static T edit(String dbName, ParamNode rootParamNode, throw new UnexpectedException(e); } finally { // restoring changes to paramNode - ParamNode.restoreRemovedChildren( removedNodesList ); + ParamNode.restoreRemovedChildren(removedNodesList); } } /** - * This method is deprecated. Use this instead: - * - * public <T extends GenericModel> T edit(ParamNode rootParamNode, String name) + * Edit a model + * + * @param name + * name of the entity + * @param params + * list of parameters + * @param + * class of the entity + * @return the entity + * + * @deprecated use method {{@link #edit(ParamNode, String)}} */ @Deprecated public T edit(String name, Map params) { ParamNode rootParamNode = ParamNode.convert(params); - return (T)edit(rootParamNode, name, this, null); + return (T) edit(rootParamNode, name, this, null); } + /** + * Edit a model + * + * @param rootParamNode + * parameters used to create the new object + * @param name + * name of the entity + * @param + * class of the entity + * @return the entity + */ public T edit(ParamNode rootParamNode, String name) { edit(rootParamNode, name, this, null); return (T) this; } + /** + * Edit a model + * + * @param dbName + * the db name + * @param rootParamNode + * parameters used to create the new object + * @param name + * name of the entity + * @param + * class of the entity + * @return the entity + */ public T edit(String dbName, ParamNode rootParamNode, String name) { edit(dbName, rootParamNode, name, this, null); return (T) this; } - - + + /** + * Validate and store the entity + * + * @return true if successful + */ public boolean validateAndSave() { if (Validation.current().valid(this).ok) { save(); @@ -218,6 +341,11 @@ public boolean validateAndSave() { return false; } + /** + * Validate and create the entity + * + * @return true if successful + */ public boolean validateAndCreate() { if (Validation.current().valid(this).ok) { return create(); @@ -227,6 +355,10 @@ public boolean validateAndCreate() { /** * store (ie insert) the entity. + * + * @param + * class of the entity + * @return true if successful */ public T save() { _save(); @@ -235,6 +367,8 @@ public T save() { /** * store (ie insert) the entity. + * + * @return true if successful */ public boolean create() { if (!em(JPA.getDBName(this.getClass())).contains(this)) { @@ -246,6 +380,10 @@ public boolean create() { /** * Refresh the entity state. + * + * @param + * class of the entity + * @return The given entity */ public T refresh() { em(JPA.getDBName(this.getClass())).refresh(this); @@ -254,6 +392,10 @@ public T refresh() { /** * Merge this object to obtain a managed entity (useful when the object comes from the Cache). + * + * @param + * class of the entity + * @return The given entity */ public T merge() { return (T) em(JPA.getDBName(this.getClass())).merge(this); @@ -261,6 +403,9 @@ public T merge() { /** * Delete the entity. + * + * @param + * class of the entity * @return The deleted entity. */ public T delete() { @@ -268,12 +413,24 @@ public T delete() { return (T) this; } + /** + * Create the new entity + * + * @param name + * name of the model + * @param params + * list of parameters + * @param + * class of the entity + * @return The created entity. + */ public static T create(String name, Params params) { throw new UnsupportedOperationException("Please annotate your JPA model with @javax.persistence.Entity annotation."); } /** * Count entities + * * @return number of entities of this class */ public static long count() { @@ -281,10 +438,12 @@ public static long count() { } /** - * Count entities with a special query. - * Example : Long moderatedPosts = Post.count("moderated", true); - * @param query HQL query or shortcut - * @param params Params to bind to the query + * Count entities with a special query. Example : Long moderatedPosts = Post.count("moderated", true); + * + * @param query + * HQL query or shortcut + * @param params + * Params to bind to the query * @return A long */ public static long count(String query, Object... params) { @@ -293,6 +452,10 @@ public static long count(String query, Object... params) { /** * Find all entities of this type + * + * @param + * the type of the entity + * @return All entities of this type */ public static List findAll() { throw new UnsupportedOperationException("Please annotate your JPA model with @javax.persistence.Entity annotation."); @@ -300,7 +463,11 @@ public static List findAll() { /** * Find the entity with the corresponding id. - * @param id The entity id + * + * @param id + * The entity id + * @param + * the type of the entity * @return The entity */ public static T findById(Object id) { @@ -309,8 +476,11 @@ public static T findById(Object id) { /** * Prepare a query to find entities. - * @param query HQL query or shortcut - * @param params Params to bind to the query + * + * @param query + * HQL query or shortcut + * @param params + * Params to bind to the query * @return A JPAQuery */ public static JPAQuery find(String query, Object... params) { @@ -319,6 +489,7 @@ public static JPAQuery find(String query, Object... params) { /** * Prepare a query to find *all* entities. + * * @return A JPAQuery */ public static JPAQuery all() { @@ -327,8 +498,11 @@ public static JPAQuery all() { /** * Batch delete of entities - * @param query HQL query or shortcut - * @param params Params to bind to the query + * + * @param query + * HQL query or shortcut + * @param params + * Params to bind to the query * @return Number of entities deleted */ public static int delete(String query, Object... params) { @@ -337,6 +511,7 @@ public static int delete(String query, Object... params) { /** * Delete all entities + * * @return Number of entities deleted */ public static int deleteAll() { @@ -374,9 +549,15 @@ public T first() { } /** - * Bind a JPQL named parameter to the current query. - * Careful, this will also bind count results. This means that Integer get transformed into long - * so hibernate can do the right thing. Use the setParameter if you just want to set parameters. + * Bind a JPQL named parameter to the current query. Careful, this will also bind count results. This means that + * Integer get transformed into long so hibernate can do the right thing. Use the setParameter if you just want + * to set parameters. + * + * @param name + * name of the object + * @param param + * current query + * @return The query */ public JPAQuery bind(String name, Object param) { if (param.getClass().isArray()) { @@ -391,7 +572,13 @@ public JPAQuery bind(String name, Object param) { /** * Set a named parameter for this query. - **/ + * + * @param name + * Parameter name + * @param param + * The given parameters + * @return The query + */ public JPAQuery setParameter(String name, Object param) { query.setParameter(name, param); return this; @@ -399,6 +586,9 @@ public JPAQuery setParameter(String name, Object param) { /** * Retrieve all results of the query + * + * @param + * the type of the entity * @return A list of entities */ public List fetch() { @@ -411,7 +601,11 @@ public List fetch() { /** * Retrieve results of the query - * @param max Max results to fetch + * + * @param max + * Max results to fetch + * @param + * The entity class * @return A list of entities */ public List fetch(int max) { @@ -425,7 +619,11 @@ public List fetch(int max) { /** * Set the position to start - * @param position Position of the first element + * + * @param position + * Position of the first element + * @param + * The entity class * @return A new query */ public JPAQuery from(int position) { @@ -435,8 +633,13 @@ public JPAQuery from(int position) { /** * Retrieve a page of result - * @param page Page number (start at 1) - * @param length (page length) + * + * @param page + * Page number (start at 1) + * @param length + * (page length) + * @param + * The entity class * @return a list of entities */ public List fetch(int page, int length) { diff --git a/framework/src/play/db/jpa/JPA.java b/framework/src/play/db/jpa/JPA.java index 2f7dfabfd5..a1fd986b58 100644 --- a/framework/src/play/db/jpa/JPA.java +++ b/framework/src/play/db/jpa/JPA.java @@ -1,16 +1,21 @@ package play.db.jpa; -import play.exceptions.JPAException; -import play.Play; -import play.Invoker.*; - -import java.util.concurrent.ConcurrentHashMap; import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; -import javax.persistence.*; +import javax.persistence.EntityManager; +import javax.persistence.EntityManagerFactory; +import javax.persistence.EntityTransaction; +import javax.persistence.FlushModeType; +import javax.persistence.PersistenceException; +import javax.persistence.PersistenceUnit; -import play.db.DB; +import play.Invoker.InvocationContext; +import play.Invoker.Suspend; import play.Logger; +import play.Play; +import play.db.DB; +import play.exceptions.JPAException; import play.libs.F; /** @@ -18,11 +23,12 @@ */ public class JPA { - protected static Map emfs = new ConcurrentHashMap<>(); + protected static Map emfs = new ConcurrentHashMap<>(); public static final ThreadLocal> currentEntityManager = new ThreadLocal>() { - @Override protected Map initialValue() { - return new ConcurrentHashMap<>(); - } + @Override + protected Map initialValue() { + return new ConcurrentHashMap<>(); + } }; public static String DEFAULT = "default"; @@ -33,7 +39,7 @@ public static class JPAContext { public boolean autoCommit = false; } - public static boolean isInitialized(){ + public static boolean isInitialized() { return get(DEFAULT) != null; } @@ -46,6 +52,8 @@ static JPAContext get(String name) { } /** + * Clear a DB context + * * @deprecated Use clearContext instead * @since 1.3.0 * @see #clearContext(String) @@ -54,10 +62,12 @@ static JPAContext get(String name) { static void clearContext() { get().clear(); } - + /** + * Clear a DB context * - * @param name : the DB name + * @param name + * the DB name */ static void clearContext(String name) { get().remove(name); @@ -66,7 +76,7 @@ static void clearContext(String name) { static void createContext(EntityManager entityManager, boolean readonly) { createContext(JPA.DEFAULT, entityManager, readonly); } - + static void createContext(String dbName, EntityManager entityManager, boolean readonly) { if (isInitialized()) { try { @@ -76,33 +86,46 @@ static void createContext(String dbName, EntityManager entityManager, boolean re } clearContext(dbName); } - bindForCurrentThread(dbName, entityManager, readonly); + bindForCurrentThread(dbName, entityManager, readonly); } public static EntityManager newEntityManager(String key) { JPAPlugin jpaPlugin = Play.plugin(JPAPlugin.class); - if(jpaPlugin == null) { + if (jpaPlugin == null) { throw new JPAException("No JPA Plugin."); } EntityManager em = jpaPlugin.em(key); - if(em == null) { + if (em == null) { throw new JPAException("No JPA EntityManagerFactory configured for name [" + key + "]"); } return em; } + /** * Get the EntityManager for specified persistence unit for this thread. + * + * @param key + * The DB name + * + * @return The EntityManager */ public static EntityManager em(String key) { - JPAContext jpaContext = get(key); - if (jpaContext == null) - throw new JPAException("No active EntityManager for name [" + key + "], transaction not started?"); - return jpaContext.entityManager; + JPAContext jpaContext = get(key); + if (jpaContext == null) + throw new JPAException("No active EntityManager for name [" + key + "], transaction not started?"); + return jpaContext.entityManager; } - /** + /** * Bind an EntityManager to the current thread. + * + * @param name + * The DB name + * @param em + * The EntityManager + * @param readonly + * indicate if it is in read only mode */ public static void bindForCurrentThread(String name, EntityManager em, boolean readonly) { JPAContext context = new JPAContext(); @@ -131,11 +154,11 @@ public static EntityManager em() { * Tell to JPA do not commit the current transaction */ public static void setRollbackOnly() { - setRollbackOnly(DEFAULT); + setRollbackOnly(DEFAULT); } public static void setRollbackOnly(String em) { - get(em).entityManager.getTransaction().setRollbackOnly(); + get(em).entityManager.getTransaction().setRollbackOnly(); } /** @@ -151,6 +174,10 @@ public static boolean isEnabled(String em) { /** * Execute a JPQL query + * + * @param query + * The query to execute + * @return The result code */ public static int execute(String query) { return execute(DEFAULT, query); @@ -160,16 +187,15 @@ public static int execute(String em, String query) { return em(em).createQuery(query).executeUpdate(); } - - // * Build a new entityManager. - // * (In most case you want to use the local entityManager with em) - + // * Build a new entityManager. + // * (In most case you want to use the local entityManager with em) + public static EntityManager newEntityManager() { return createEntityManager(); } public static EntityManager createEntityManager() { - return createEntityManager(JPA.DEFAULT); + return createEntityManager(JPA.DEFAULT); } public static EntityManager createEntityManager(String name) { @@ -192,9 +218,9 @@ public static boolean isInsideTransaction(String name) { } public static T withinFilter(F.Function0 block) throws Throwable { - if(InvocationContext.current().getAnnotation(NoTransaction.class) != null ) { - //Called method or class is annotated with @NoTransaction telling us that - //we should not start a transaction + if (InvocationContext.current().getAnnotation(NoTransaction.class) != null) { + // Called method or class is annotated with @NoTransaction telling us that + // we should not start a transaction return block.apply(); } @@ -212,11 +238,10 @@ public static T withinFilter(F.Function0 block) throws Throwable { return withTransaction(name, readOnly, block); } - public static String getDBName(Class clazz) { String name = JPA.DEFAULT; - if(clazz != null){ - PersistenceUnit pu = (PersistenceUnit)clazz.getAnnotation(PersistenceUnit.class); + if (clazz != null) { + PersistenceUnit pu = clazz.getAnnotation(PersistenceUnit.class); if (pu != null) { name = pu.name(); } @@ -224,19 +249,26 @@ public static String getDBName(Class clazz) { return name; } - /** * Run a block of code in a JPA transaction. * - * @param dbName The persistence unit name - * @param readOnly Is the transaction read-only? - * @param block Block of code to execute. + * @param dbName + * The persistence unit name + * @param readOnly + * Is the transaction read-only? + * @param block + * Block of code to execute. + * @param + * The entity class + * @return The result + * @throws java.lang.Throwable + * Thrown in case of error */ public static T withTransaction(String dbName, boolean readOnly, F.Function0 block) throws Throwable { if (isEnabled()) { boolean closeEm = true; // For each existing persistence unit - + try { // we are starting a transaction for all known persistent unit // this is probably not the best, but there is no way we can know where to go from @@ -251,14 +283,15 @@ public static T withTransaction(String dbName, boolean readOnly, F.Function0 } T result = block.apply(); - + boolean rollbackAll = false; // Get back our entity managers // Because people might have mess up with the current entity managers for (JPAContext jpaContext : get().values()) { EntityManager m = jpaContext.entityManager; EntityTransaction localTx = m.getTransaction(); - // The resource transaction must be in progress in order to determine if it has been marked for rollback + // The resource transaction must be in progress in order to determine if it has been marked for + // rollback if (localTx.isActive() && localTx.getRollbackOnly()) { rollbackAll = true; } @@ -283,7 +316,7 @@ public static T withTransaction(String dbName, boolean readOnly, F.Function0 // Nothing, transaction is in progress closeEm = false; throw e; - } catch(Throwable t) { + } catch (Throwable t) { // Because people might have mess up with the current entity managers for (JPAContext jpaContext : get().values()) { EntityManager m = jpaContext.entityManager; @@ -293,7 +326,7 @@ public static T withTransaction(String dbName, boolean readOnly, F.Function0 if (localTx.isActive()) { localTx.rollback(); } - } catch(Throwable e) { + } catch (Throwable e) { } } @@ -310,18 +343,20 @@ public static T withTransaction(String dbName, boolean readOnly, F.Function0 for (String name : emfs.keySet()) { JPA.unbindForCurrentThread(name); } - } - } + } + } } else { return block.apply(); } } - /** + /** * initialize the JPA context and starts a JPA transaction * - * @param name The persistence unit name - * @param readOnly true for a readonly transaction + * @param name + * The persistence unit name + * @param readOnly + * true for a readonly transaction */ public static void startTx(String name, boolean readOnly) { EntityManager manager = createEntityManager(name); @@ -333,15 +368,16 @@ public static void startTx(String name, boolean readOnly) { public static void closeTx(String name) { if (JPA.isInsideTransaction(name)) { - EntityManager manager = em(name); - try { - // Be sure to set the connection is non-autoCommit mode as some driver will complain about COMMIT statement + EntityManager manager = em(name); + try { + // Be sure to set the connection is non-autoCommit mode as some driver will complain about COMMIT + // statement try { DB.getConnection(name).setAutoCommit(false); - } catch(Exception e) { + } catch (Exception e) { Logger.error(e, "Why the driver complains here?"); } - // Commit the transaction + // Commit the transaction if (manager.getTransaction().isActive()) { if (JPA.get().get(name).readonly || manager.getTransaction().getRollbackOnly()) { manager.getTransaction().rollback(); @@ -374,19 +410,20 @@ public static void closeTx(String name) { public static void rollbackTx(String name) { if (JPA.isInsideTransaction()) { - EntityManager manager = em(name); - try { - // Be sure to set the connection is non-autoCommit mode as some driver will complain about COMMIT statement + EntityManager manager = em(name); + try { + // Be sure to set the connection is non-autoCommit mode as some driver will complain about COMMIT + // statement try { DB.getConnection(name).setAutoCommit(false); - } catch(Exception e) { + } catch (Exception e) { Logger.error(e, "Why the driver complains here?"); } - // Commit the transaction + // Commit the transaction if (manager.getTransaction().isActive()) { try { - manager.getTransaction().rollback(); - } catch (Throwable e) { + manager.getTransaction().rollback(); + } catch (Throwable e) { for (int i = 0; i < 10; i++) { if (e instanceof PersistenceException && e.getCause() != null) { e = e.getCause(); @@ -400,7 +437,7 @@ public static void rollbackTx(String name) { throw new JPAException("Cannot commit", e); } } - + } finally { if (manager.isOpen()) { manager.close(); diff --git a/framework/src/play/db/jpa/JPABase.java b/framework/src/play/db/jpa/JPABase.java index 8024f5a03b..3b30a0217d 100644 --- a/framework/src/play/db/jpa/JPABase.java +++ b/framework/src/play/db/jpa/JPABase.java @@ -1,8 +1,29 @@ package play.db.jpa; -import org.hibernate.collection.spi.PersistentCollection; +import java.io.Serializable; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.sql.SQLException; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import javax.persistence.CascadeType; +import javax.persistence.EntityManager; +import javax.persistence.ManyToMany; +import javax.persistence.ManyToOne; +import javax.persistence.MappedSuperclass; +import javax.persistence.OneToMany; +import javax.persistence.OneToOne; +import javax.persistence.PersistenceException; + import org.hibernate.collection.internal.PersistentMap; -import org.hibernate.engine.spi.*; +import org.hibernate.collection.spi.PersistentCollection; +import org.hibernate.engine.spi.CollectionEntry; +import org.hibernate.engine.spi.EntityEntry; import org.hibernate.engine.spi.PersistenceContext; import org.hibernate.exception.GenericJDBCException; import org.hibernate.internal.SessionImpl; @@ -14,14 +35,6 @@ import play.PlayPlugin; import play.exceptions.UnexpectedException; -import javax.persistence.*; - -import java.io.Serializable; -import java.lang.reflect.Field; -import java.lang.reflect.Modifier; -import java.sql.SQLException; -import java.util.*; - /** * A super class for JPA entities */ @@ -61,7 +74,7 @@ public void _save() { @Override public void _delete() { String dbName = JPA.getDBName(this.getClass()); - + try { avoidCascadeSaveLoops.set(new HashSet()); try { @@ -188,7 +201,7 @@ private void saveAndCascade(boolean willBeSaved) { private void cascadeOrphans(JPABase base, PersistentCollection persistentCollection, boolean willBeSaved) { String dbName = JPA.getDBName(this.getClass()); - + SessionImpl session = ((SessionImpl) JPA.em(dbName).getDelegate()); PersistenceContext pc = session.getPersistenceContext(); CollectionEntry ce = pc.getCollectionEntry(persistentCollection); @@ -199,7 +212,7 @@ private void cascadeOrphans(JPABase base, PersistentCollection persistentCollect Type ct = cp.getElementType(); if (ct instanceof EntityType) { EntityEntry entry = pc.getEntry(base); - String entityName = entry.getEntityName(); + String entityName = entry.getEntityName(); entityName = ((EntityType) ct).getAssociatedEntityName(session.getFactory()); if (ce.getSnapshot() != null) { Collection orphans = ce.getOrphans(entityName, persistentCollection); @@ -229,6 +242,9 @@ private static boolean cascadeAll(CascadeType[] types) { /** * Retrieve the current entityManager + * + * @param name + * The DB name * * @return the current entityManager */ @@ -236,7 +252,7 @@ public static EntityManager em(String name) { return JPA.em(name); } - public static EntityManager em() { + public static EntityManager em() { return JPA.em(); } @@ -249,9 +265,11 @@ public boolean isPersistent() { } /** - * JPASupport instances a and b are equals if either a == b or a and b have same {@link #_key key} and class + * JPASupport instances a and b are equals if either a == b or a and b have same + * {@link #_key key} and class * * @param other + * The object to compare to * @return true if equality condition above is verified */ @Override @@ -275,7 +293,6 @@ public boolean equals(Object other) { return false; } - if (!this.getClass().isAssignableFrom(other.getClass())) { return false; } diff --git a/framework/src/play/db/jpa/NoTransaction.java b/framework/src/play/db/jpa/NoTransaction.java index 544e02e0e7..29f7027bc8 100644 --- a/framework/src/play/db/jpa/NoTransaction.java +++ b/framework/src/play/db/jpa/NoTransaction.java @@ -1,6 +1,5 @@ package play.db.jpa; - import java.lang.annotation.ElementType; import java.lang.annotation.Inherited; import java.lang.annotation.Retention; @@ -8,16 +7,16 @@ import java.lang.annotation.Target; /** - * Annotation to be used on methods telling JPA - * that it should not create a Transaction at all + * Annotation to be used on methods telling JPA that it should not create a Transaction at all */ @Retention(RetentionPolicy.RUNTIME) @Inherited -@Target(value = {ElementType.METHOD, ElementType.TYPE}) +@Target(value = { ElementType.METHOD, ElementType.TYPE }) public @interface NoTransaction { /** * Db name we do not want transaction. + * + * @return The DB name */ String value() default "default"; } - diff --git a/framework/src/play/db/jpa/Transactional.java b/framework/src/play/db/jpa/Transactional.java index 588254fcef..f940197684 100644 --- a/framework/src/play/db/jpa/Transactional.java +++ b/framework/src/play/db/jpa/Transactional.java @@ -6,13 +6,14 @@ import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME) -@Target({ElementType.METHOD, ElementType.TYPE}) +@Target({ ElementType.METHOD, ElementType.TYPE }) public @interface Transactional { /** * Db name where to persist for multi db support + * + * @return The DB name */ String value() default "default"; public boolean readOnly() default false; } - diff --git a/framework/src/play/inject/Injector.java b/framework/src/play/inject/Injector.java index ec290e2156..a9e34dfc1a 100644 --- a/framework/src/play/inject/Injector.java +++ b/framework/src/play/inject/Injector.java @@ -4,16 +4,21 @@ import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.List; + import javax.inject.Inject; + import play.Play; import play.classloading.enhancers.ControllersEnhancer.ControllerSupport; import play.jobs.Job; import play.mvc.Mailer; public class Injector { - + /** * For now, inject beans in controllers + * + * @param source + * the beanSource to inject */ public static void inject(BeanSource source) { List classes = new ArrayList<>(Play.classloader.getAssignableClasses(ControllerSupport.class)); @@ -26,9 +31,9 @@ public static void inject(BeanSource source) { field.setAccessible(true); try { field.set(null, source.getBeanOfType(type)); - } catch(RuntimeException e) { + } catch (RuntimeException e) { throw e; - } catch(Exception e) { + } catch (Exception e) { throw new RuntimeException(e); } } diff --git a/framework/src/play/jobs/Job.java b/framework/src/play/jobs/Job.java index 4bf7f220e3..901ce062b8 100644 --- a/framework/src/play/jobs/Job.java +++ b/framework/src/play/jobs/Job.java @@ -5,10 +5,15 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; + +import com.jamonapi.Monitor; +import com.jamonapi.MonitorFactory; + import play.Invoker; import play.Invoker.InvocationContext; import play.Logger; import play.Play; +import play.PlayPlugin; import play.exceptions.JavaExecutionException; import play.exceptions.PlayException; import play.exceptions.UnexpectedException; @@ -16,14 +21,12 @@ import play.libs.F.Promise; import play.libs.Time; import play.mvc.Http; -import play.PlayPlugin; - -import com.jamonapi.Monitor; -import com.jamonapi.MonitorFactory; /** * A job is an asynchronously executed unit of work - * @param The job result type (if any) + * + * @param + * The job result type (if any) */ public class Job extends Invoker.Invocation implements Callable { @@ -43,12 +46,19 @@ public InvocationContext getInvocationContext() { /** * Here you do the job + * + * @throws Exception + * if problems occurred */ public void doJob() throws Exception { } /** * Here you do the job and return a result + * + * @return The job result + * @throws Exception + * if problems occurred */ public V doJobWithResult() throws Exception { doJob(); @@ -57,11 +67,12 @@ public V doJobWithResult() throws Exception { @Override public void execute() throws Exception { - + } /** * Start this job now (well ASAP) + * * @return the job completion */ public Promise now() { @@ -70,31 +81,33 @@ public Promise now() { return smartFuture; } - /** - * If is called in a 'HttpRequest' invocation context, waits until request - * is served and schedules job then. - * - * Otherwise is the same as now(); - * - * If you want to schedule a job to run after some other job completes, wait till a promise redeems - * of just override first Job's call() to schedule the second one. - * - * @return the job completion - */ - public Promise afterRequest() { - InvocationContext current = Invoker.InvocationContext.current(); - if(current == null || !Http.invocationType.equals(current.getInvocationType())) { - return now(); - } + /** + * If is called in a 'HttpRequest' invocation context, waits until request is served and schedules job then. + * + * Otherwise is the same as now(); + * + * If you want to schedule a job to run after some other job completes, wait till a promise redeems of just override + * first Job's call() to schedule the second one. + * + * @return the job completion + */ + public Promise afterRequest() { + InvocationContext current = Invoker.InvocationContext.current(); + if (current == null || !Http.invocationType.equals(current.getInvocationType())) { + return now(); + } - Promise smartFuture = new Promise<>(); - Callable callable = getJobCallingCallable(smartFuture); - JobsPlugin.addAfterRequestAction(callable); - return smartFuture; - } + Promise smartFuture = new Promise<>(); + Callable callable = getJobCallingCallable(smartFuture); + JobsPlugin.addAfterRequestAction(callable); + return smartFuture; + } /** * Start this job in several seconds + * + * @param delay + * time in seconds * @return the job completion */ public Promise in(String delay) { @@ -103,6 +116,9 @@ public Promise in(String delay) { /** * Start this job in several seconds + * + * @param seconds + * time in seconds * @return the job completion */ public Promise in(int seconds) { @@ -112,28 +128,30 @@ public Promise in(int seconds) { } private Callable getJobCallingCallable(final Promise smartFuture) { - return new Callable() { - @Override - public V call() throws Exception { - try { - V result = Job.this.call(); - if (smartFuture != null) { - smartFuture.invoke(result); + return new Callable() { + @Override + public V call() throws Exception { + try { + V result = Job.this.call(); + if (smartFuture != null) { + smartFuture.invoke(result); + } + return result; + } catch (Exception e) { + if (smartFuture != null) { + smartFuture.invokeWithException(e); + } + return null; + } } - return result; - } - catch (Exception e) { - if (smartFuture != null) { - smartFuture.invokeWithException(e); - } - return null; - } - } - }; + }; } /** * Run this job every n seconds + * + * @param delay + * time in seconds */ public void every(String delay) { every(Time.parseDuration(delay)); @@ -141,6 +159,9 @@ public void every(String delay) { /** * Run this job every n seconds + * + * @param seconds + * time in seconds */ public void every(int seconds) { JobsPlugin.executor.scheduleWithFixedDelay(this, seconds, seconds, TimeUnit.SECONDS); @@ -154,17 +175,17 @@ public void onException(Throwable e) { lastException = e; try { super.onException(e); - } catch(Throwable ex) { + } catch (Throwable ex) { Logger.error(ex, "Error during job execution (%s)", this); throw new UnexpectedException(unwrap(e)); } } private Throwable unwrap(Throwable e) { - while((e instanceof UnexpectedException || e instanceof PlayException) && e.getCause() != null) { - e = e.getCause(); - } - return e; + while ((e instanceof UnexpectedException || e instanceof PlayException) && e.getCause() != null) { + e = e.getCause(); + } + return e; } @Override @@ -172,19 +193,14 @@ public void run() { call(); } - - - - - - private V withinFilter(play.libs.F.Function0 fct) throws Throwable { - F.Option> filters = Play.pluginCollection.composeFilters(); - if (!filters.isDefined()) { - return null; - } else { - return filters.get().withinFilter(fct); + private V withinFilter(play.libs.F.Function0 fct) throws Throwable { + F.Option> filters = Play.pluginCollection.composeFilters(); + if (!filters.isDefined()) { + return null; + } else { + return filters.get().withinFilter(fct); + } } - } @Override public V call() { @@ -198,8 +214,8 @@ public V call() { lastException = null; lastRun = System.currentTimeMillis(); monitor = MonitorFactory.start(this + ".doJob()"); - - // If we have a plugin, get him to execute the job within the filter. + + // If we have a plugin, get him to execute the job within the filter. final AtomicBoolean executed = new AtomicBoolean(false); result = this.withinFilter(new play.libs.F.Function0() { @Override @@ -208,12 +224,12 @@ public V apply() throws Throwable { return doJobWithResult(); } }); - + // No filter function found => we need to execute anyway( as before the use of withinFilter ) if (!executed.get()) { result = doJobWithResult(); } - + monitor.stop(); monitor = null; wasError = false; @@ -222,7 +238,8 @@ public V apply() throws Throwable { } catch (Exception e) { StackTraceElement element = PlayException.getInterestingStackTraceElement(e); if (element != null) { - throw new JavaExecutionException(Play.classes.getApplicationClass(element.getClassName()), element.getLineNumber(), e); + throw new JavaExecutionException(Play.classes.getApplicationClass(element.getClassName()), element.getLineNumber(), + e); } throw e; } @@ -232,7 +249,7 @@ public V apply() throws Throwable { } catch (Throwable e) { onException(e); } finally { - if(monitor != null) { + if (monitor != null) { monitor.stop(); } _finally(); @@ -253,5 +270,4 @@ public String toString() { return this.getClass().getName(); } - } diff --git a/framework/src/play/libs/Codec.java b/framework/src/play/libs/Codec.java index 3ac425599c..8ee82e3e95 100644 --- a/framework/src/play/libs/Codec.java +++ b/framework/src/play/libs/Codec.java @@ -7,6 +7,7 @@ import org.apache.commons.codec.DecoderException; import org.apache.commons.codec.binary.Base64; import org.apache.commons.codec.binary.Hex; + import play.exceptions.UnexpectedException; /** @@ -15,6 +16,8 @@ public class Codec { /** + * Generate an UUID String + * * @return an UUID String */ public static String UUID() { @@ -23,7 +26,9 @@ public static String UUID() { /** * Encode a String to base64 - * @param value The plain String + * + * @param value + * The plain String * @return The base64 encoded String */ public static String encodeBASE64(String value) { @@ -35,8 +40,10 @@ public static String encodeBASE64(String value) { } /** - * Encode binary data to base64 - * @param value The binary data + * Encode binary data to base64 + * + * @param value + * The binary data * @return The base64 encoded String */ public static String encodeBASE64(byte[] value) { @@ -45,7 +52,9 @@ public static String encodeBASE64(byte[] value) { /** * Decode a base64 value - * @param value The base64 encoded String + * + * @param value + * The base64 encoded String * @return decoded binary data */ public static byte[] decodeBASE64(String value) { @@ -58,7 +67,9 @@ public static byte[] decodeBASE64(String value) { /** * Build an hexadecimal MD5 hash for a String - * @param value The String to hash + * + * @param value + * The String to hash * @return An hexadecimal Hash */ public static String hexMD5(String value) { @@ -75,9 +86,11 @@ public static String hexMD5(String value) { /** * Build an hexadecimal SHA1 hash for a String - * @param value The String to hash + * + * @param value + * The String to hash * @return An hexadecimal Hash - */ + */ public static String hexSHA1(String value) { try { MessageDigest md; @@ -92,6 +105,10 @@ public static String hexSHA1(String value) { /** * Write a byte array as hexadecimal String. + * + * @param bytes + * byte array + * @return The hexadecimal String */ public static String byteToHexString(byte[] bytes) { return String.valueOf(Hex.encodeHex(bytes)); @@ -99,6 +116,10 @@ public static String byteToHexString(byte[] bytes) { /** * Transform an hexadecimal String to a byte array. + * + * @param hexString + * Hexadecimal string to transform + * @return The byte array */ public static byte[] hexStringToByte(String hexString) { try { diff --git a/framework/src/play/libs/CronExpression.java b/framework/src/play/libs/CronExpression.java index ab26816701..a31de92202 100644 --- a/framework/src/play/libs/CronExpression.java +++ b/framework/src/play/libs/CronExpression.java @@ -18,14 +18,14 @@ /** * Thanks to Quartz project, https://quartz.dev.java.net *

- * Provides a parser and evaluator for unix-like cron expressions. Cron - * expressions provide the ability to specify complex time combinations such as - * "At 8:00am every Monday through Friday" or "At 1:30am every - * last Friday of the month". - *

- * Cron expressions are comprised of 6 required fields and one optional field - * separated by white space. The fields respectively are described as follows: + * Provides a parser and evaluator for unix-like cron expressions. Cron expressions provide the ability to specify + * complex time combinations such as "At 8:00am every Monday through Friday" or "At 1:30am every last + * Friday of the month". + *

*

+ * Cron expressions are comprised of 6 required fields and one optional field separated by white space. The fields + * respectively are described as follows: + *

* * * @@ -85,85 +85,77 @@ * *
Field Name
*

- * The '*' character is used to specify all values. For example, "*" - * in the minute field means "every minute". - *

- * The '?' character is allowed for the day-of-month and day-of-week fields. It - * is used to specify 'no specific value'. This is useful when you need to - * specify something in one of the two fileds, but not the other. + * The '*' character is used to specify all values. For example, "*" in the minute field means "every + * minute". + *

*

- * The '-' character is used to specify ranges For example "10-12" in - * the hour field means "the hours 10, 11 and 12". + * The '?' character is allowed for the day-of-month and day-of-week fields. It is used to specify 'no specific value'. + * This is useful when you need to specify something in one of the two fileds, but not the other. + *

*

- * The ',' character is used to specify additional values. For example - * "MON,WED,FRI" in the day-of-week field means "the days Monday, - * Wednesday, and Friday". + * The '-' character is used to specify ranges For example "10-12" in the hour field means "the hours 10, + * 11 and 12". + *

*

- * The '/' character is used to specify increments. For example "0/15" - * in the seconds field means "the seconds 0, 15, 30, and 45". And - * "5/15" in the seconds field means "the seconds 5, 20, 35, and - * 50". Specifying '*' before the '/' is equivalent to specifying 0 is the - * value to start with. Essentially, for each field in the expression, there is - * a set of numbers that can be turned on or off. For seconds and minutes, the - * numbers range from 0 to 59. For hours 0 to 23, for days of the month 0 to 31, - * and for months 1 to 12. The "/" character simply helps you turn on - * every "nth" value in the given set. Thus "7/6" in the - * month field only turns on month "7", it does NOT mean every 6th - * month, please note that subtlety. + * The ',' character is used to specify additional values. For example "MON,WED,FRI" in the day-of-week field + * means "the days Monday, Wednesday, and Friday". + *

*

- * The 'L' character is allowed for the day-of-month and day-of-week fields. - * This character is short-hand for "last", but it has different - * meaning in each of the two fields. For example, the value "L" in - * the day-of-month field means "the last day of the month" - day 31 - * for January, day 28 for February on non-leap years. If used in the - * day-of-week field by itself, it simply means "7" or - * "SAT". But if used in the day-of-week field after another value, it - * means "the last xxx day of the month" - for example "6L" - * means "the last friday of the month". When using the 'L' option, it - * is important not to specify lists, or ranges of values, as you'll get - * confusing results. + * The '/' character is used to specify increments. For example "0/15" in the seconds field means "the + * seconds 0, 15, 30, and 45". And "5/15" in the seconds field means "the seconds 5, 20, 35, and + * 50". Specifying '*' before the '/' is equivalent to specifying 0 is the value to start with. Essentially, for + * each field in the expression, there is a set of numbers that can be turned on or off. For seconds and minutes, the + * numbers range from 0 to 59. For hours 0 to 23, for days of the month 0 to 31, and for months 1 to 12. The + * "/" character simply helps you turn on every "nth" value in the given set. Thus "7/6" + * in the month field only turns on month "7", it does NOT mean every 6th month, please note that subtlety. + *

*

- * The 'W' character is allowed for the day-of-month field. This character is - * used to specify the weekday (Monday-Friday) nearest the given day. As an - * example, if you were to specify "15W" as the value for the - * day-of-month field, the meaning is: "the nearest weekday to the 15th of - * the month". So if the 15th is a Saturday, the trigger will fire on - * Friday the 14th. If the 15th is a Sunday, the trigger will fire on Monday the - * 16th. If the 15th is a Tuesday, then it will fire on Tuesday the 15th. - * However if you specify "1W" as the value for day-of-month, and the - * 1st is a Saturday, the trigger will fire on Monday the 3rd, as it will not - * 'jump' over the boundary of a month's days. The 'W' character can only be - * specified when the day-of-month is a single day, not a range or list of days. + * The 'L' character is allowed for the day-of-month and day-of-week fields. This character is short-hand for + * "last", but it has different meaning in each of the two fields. For example, the value "L" in the + * day-of-month field means "the last day of the month" - day 31 for January, day 28 for February on non-leap + * years. If used in the day-of-week field by itself, it simply means "7" or "SAT". But if used in + * the day-of-week field after another value, it means "the last xxx day of the month" - for example + * "6L" means "the last friday of the month". When using the 'L' option, it is important not to + * specify lists, or ranges of values, as you'll get confusing results. + *

*

- * The 'L' and 'W' characters can also be combined for the day-of-month - * expression to yield 'LW', which translates to "last weekday of the - * month". + * The 'W' character is allowed for the day-of-month field. This character is used to specify the weekday + * (Monday-Friday) nearest the given day. As an example, if you were to specify "15W" as the value for the + * day-of-month field, the meaning is: "the nearest weekday to the 15th of the month". So if the 15th is a + * Saturday, the trigger will fire on Friday the 14th. If the 15th is a Sunday, the trigger will fire on Monday the + * 16th. If the 15th is a Tuesday, then it will fire on Tuesday the 15th. However if you specify "1W" as the + * value for day-of-month, and the 1st is a Saturday, the trigger will fire on Monday the 3rd, as it will not 'jump' + * over the boundary of a month's days. The 'W' character can only be specified when the day-of-month is a single day, + * not a range or list of days. + *

*

- * The '#' character is allowed for the day-of-week field. This character is - * used to specify "the nth" xxx day of the month. For example, the - * value of "6#3" in the day-of-week field means the third Friday of - * the month (day 6 = Friday and "#3" = the 3rd one in the month). - * Other examples: "2#1" = the first Monday of the month and - * "4#5" = the fifth Wednesday of the month. Note that if you specify - * "#5" and there is not 5 of the given day-of-week in the month, then - * no firing will occur that month. + * The 'L' and 'W' characters can also be combined for the day-of-month expression to yield 'LW', which translates to + * "last weekday of the month". + *

*

- * + * The '#' character is allowed for the day-of-week field. This character is used to specify "the nth" xxx day + * of the month. For example, the value of "6#3" in the day-of-week field means the third Friday of the month + * (day 6 = Friday and "#3" = the 3rd one in the month). Other examples: "2#1" = the first Monday of + * the month and "4#5" = the fifth Wednesday of the month. Note that if you specify "#5" and there + * is not 5 of the given day-of-week in the month, then no firing will occur that month. + *

+ * *

+ * The legal characters and the names of months and days of the week are not case sensitive. + *

+ * * NOTES: *
    - *
  • Support for specifying both a day-of-week and a day-of-month value is not - * complete (you'll need to use the '?' character in on of these fields).
  • + *
  • Support for specifying both a day-of-week and a day-of-month value is not complete (you'll need to use the '?' + * character in on of these fields).
  • *
* * @author Sharada Jambula, James House @@ -225,15 +217,12 @@ public class CronExpression implements Serializable, Cloneable { protected transient boolean expressionParsed = false; /** - * Constructs a new CronExpression based on the specified - * parameter. + * Constructs a new CronExpression based on the specified parameter. * * @param cronExpression - * String representation of the cron expression the new object - * should represent + * String representation of the cron expression the new object should represent * @throws java.text.ParseException - * if the string expression cannot be parsed into a valid - * CronExpression + * if the string expression cannot be parsed into a valid CronExpression */ public CronExpression(String cronExpression) throws ParseException { if (cronExpression == null) { @@ -246,14 +235,12 @@ public CronExpression(String cronExpression) throws ParseException { } /** - * Indicates whether the given date satisfies the cron expression. Note that - * milliseconds are ignored, so two Dates falling on different milliseconds - * of the same second will always have the same result here. + * Indicates whether the given date satisfies the cron expression. Note that milliseconds are ignored, so two Dates + * falling on different milliseconds of the same second will always have the same result here. * * @param date * the date to evaluate - * @return a boolean indicating whether the given date satisfies the cron - * expression + * @return a boolean indicating whether the given date satisfies the cron expression */ public boolean isSatisfiedBy(Date date) { Calendar testDateCal = Calendar.getInstance(); @@ -269,12 +256,10 @@ public boolean isSatisfiedBy(Date date) { } /** - * Returns the next date/time after the given date/time which - * satisfies the cron expression. + * Returns the next date/time after the given date/time which satisfies the cron expression. * * @param date - * the date/time at which to begin the search for the next valid - * date/time + * the date/time at which to begin the search for the next valid date/time * @return the next valid date/time */ public Date getNextValidTimeAfter(Date date) { @@ -282,12 +267,10 @@ public Date getNextValidTimeAfter(Date date) { } /** - * Returns the next date/time after the given date/time which does - * not satisfy the expression + * Returns the next date/time after the given date/time which does not satisfy the expression * * @param date - * the date/time at which to begin the search for the next - * invalid date/time + * the date/time at which to begin the search for the next invalid date/time * @return the next valid date/time */ public Date getNextInvalidTimeAfter(Date date) { @@ -324,8 +307,7 @@ public Date getNextInvalidTimeAfter(Date date) { * * @param date * the date/time at which to begin the search - * @return the number of milliseconds between the next valid and the one - * after + * @return the number of milliseconds between the next valid and the one after */ public long getNextInterval(Date date) { Date nextValid = getNextValidTimeAfter(date); @@ -335,8 +317,9 @@ public long getNextInterval(Date date) { } /** - * Returns the time zone for which this CronExpression will be - * resolved. + * Returns the time zone for which this CronExpression will be resolved. + * + * @return Returns the time zone */ public TimeZone getTimeZone() { if (timeZone == null) { @@ -347,8 +330,10 @@ public TimeZone getTimeZone() { } /** - * Sets the time zone for which this CronExpression will be - * resolved. + * Sets the time zone for which this CronExpression will be resolved. + * + * @param timeZone + * The given time zone */ public void setTimeZone(TimeZone timeZone) { this.timeZone = timeZone; @@ -365,13 +350,11 @@ public String toString() { } /** - * Indicates whether the specified cron expression can be parsed into a - * valid cron expression + * Indicates whether the specified cron expression can be parsed into a valid cron expression * * @param cronExpression * the expression to evaluate - * @return a boolean indicating whether the given expression is a valid cron - * expression + * @return a boolean indicating whether the given expression is a valid cron expression */ public static boolean isValidExpression(String cronExpression) { @@ -1402,11 +1385,12 @@ protected Date getTimeAfter(Date afterTime) { } /** - * Advance the calendar to the particular hour paying particular attention - * to daylight saving problems. + * Advance the calendar to the particular hour paying particular attention to daylight saving problems. * * @param cal + * The given calendar * @param hour + * The hour to set */ protected void setCalendarHour(Calendar cal, int hour) { cal.set(java.util.Calendar.HOUR_OF_DAY, hour); @@ -1416,16 +1400,20 @@ protected void setCalendarHour(Calendar cal, int hour) { } /** - * NOT YET IMPLEMENTED: Returns the time before the given time that the - * CronExpression matches. + * NOT YET IMPLEMENTED: Returns the time before the given time that the CronExpression matches. + * + * @param endTime + * The given time + * @return Returns the time before the given time */ protected Date getTimeBefore(Date endTime) { throw new NotImplementedException(); } /** - * NOT YET IMPLEMENTED: Returns the final time that the - * CronExpression will match. + * NOT YET IMPLEMENTED: Returns the final time that the CronExpression will match. + * + * @return Returns the final time */ public Date getFinalFireTime() { throw new NotImplementedException(); diff --git a/framework/src/play/libs/Crypto.java b/framework/src/play/libs/Crypto.java index cc6cd50f60..f12a8cc482 100644 --- a/framework/src/play/libs/Crypto.java +++ b/framework/src/play/libs/Crypto.java @@ -3,12 +3,12 @@ import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; -import org.apache.commons.codec.binary.Base64; - import javax.crypto.Cipher; import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; +import org.apache.commons.codec.binary.Base64; + import play.Play; import play.exceptions.UnexpectedException; @@ -21,13 +21,17 @@ public class Crypto { * Define a hash type enumeration for strong-typing */ public enum HashType { - MD5("MD5"), - SHA1("SHA-1"), - SHA256("SHA-256"), - SHA512("SHA-512"); + MD5("MD5"), SHA1("SHA-1"), SHA256("SHA-256"), SHA512("SHA-512"); private String algorithm; - HashType(String algorithm) { this.algorithm = algorithm; } - @Override public String toString() { return this.algorithm; } + + HashType(String algorithm) { + this.algorithm = algorithm; + } + + @Override + public String toString() { + return this.algorithm; + } } /** @@ -35,10 +39,14 @@ public enum HashType { */ private static final HashType DEFAULT_HASH_TYPE = HashType.MD5; - static final char[] HEX_CHARS = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; + static final char[] HEX_CHARS = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; /** * Sign a message using the application secret key (HMAC-SHA1) + * + * @param message + * the message to sign + * @return The signed message */ public static String sign(String message) { return sign(message, Play.secretKey.getBytes()); @@ -46,8 +54,11 @@ public static String sign(String message) { /** * Sign a message with a key - * @param message The message to sign - * @param key The key to use + * + * @param message + * The message to sign + * @param key + * The key to use * @return The signed message (in hexadecimal) */ public static String sign(String message, byte[] key) { @@ -65,7 +76,6 @@ public static String sign(String message, byte[] key) { int len = result.length; char[] hexChars = new char[len * 2]; - for (int charIndex = 0, startIndex = 0; charIndex < hexChars.length;) { int bite = result[startIndex++] & 0xff; hexChars[charIndex++] = HEX_CHARS[bite >> 4]; @@ -79,23 +89,26 @@ public static String sign(String message, byte[] key) { } /** - * Create a password hash using the default hashing algorithm - * @param input The password - * @return The password hash - */ - public static String passwordHash(String input) - { + * Create a password hash using the default hashing algorithm + * + * @param input + * The password + * @return The password hash + */ + public static String passwordHash(String input) { return passwordHash(input, DEFAULT_HASH_TYPE); } /** - * Create a password hash using specific hashing algorithm - * @param input The password - * @param hashType The hashing algorithm - * @return The password hash - */ - public static String passwordHash(String input, HashType hashType) - { + * Create a password hash using specific hashing algorithm + * + * @param input + * The password + * @param hashType + * The hashing algorithm + * @return The password hash + */ + public static String passwordHash(String input, HashType hashType) { try { MessageDigest m = MessageDigest.getInstance(hashType.toString()); byte[] out = m.digest(input.getBytes()); @@ -107,7 +120,9 @@ public static String passwordHash(String input, HashType hashType) /** * Encrypt a String with the AES encryption standard using the application secret - * @param value The String to encrypt + * + * @param value + * The String to encrypt * @return An hexadecimal encrypted string */ public static String encryptAES(String value) { @@ -116,8 +131,11 @@ public static String encryptAES(String value) { /** * Encrypt a String with the AES encryption standard. Private key must have a length of 16 bytes - * @param value The String to encrypt - * @param privateKey The key used to encrypt + * + * @param value + * The String to encrypt + * @param privateKey + * The key used to encrypt * @return An hexadecimal encrypted string */ public static String encryptAES(String value, String privateKey) { @@ -134,7 +152,9 @@ public static String encryptAES(String value, String privateKey) { /** * Decrypt a String with the AES encryption standard using the application secret - * @param value An hexadecimal encrypted string + * + * @param value + * An hexadecimal encrypted string * @return The decrypted String */ public static String decryptAES(String value) { @@ -143,8 +163,11 @@ public static String decryptAES(String value) { /** * Decrypt a String with the AES encryption standard. Private key must have a length of 16 bytes - * @param value An hexadecimal encrypted string - * @param privateKey The key used to encrypt + * + * @param value + * An hexadecimal encrypted string + * @param privateKey + * The key used to encrypt * @return The decrypted String */ public static String decryptAES(String value, String privateKey) { diff --git a/framework/src/play/libs/Files.java b/framework/src/play/libs/Files.java index 06e6b2190e..eced3d1a7c 100644 --- a/framework/src/play/libs/Files.java +++ b/framework/src/play/libs/Files.java @@ -1,16 +1,20 @@ package play.libs; -import org.apache.commons.io.FileUtils; -import org.apache.commons.io.IOUtils; -import play.exceptions.UnexpectedException; +import static org.apache.commons.io.FileUtils.copyInputStreamToFile; -import java.io.*; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; import java.util.Enumeration; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import java.util.zip.ZipOutputStream; -import static org.apache.commons.io.FileUtils.copyInputStreamToFile; +import org.apache.commons.io.FileUtils; +import org.apache.commons.io.IOUtils; + +import play.exceptions.UnexpectedException; /** * Files utils @@ -20,15 +24,18 @@ public class Files { /** * Characters that are invalid in Windows OS file names (Unix only forbids '/' character) */ - public static final char[] ILLEGAL_FILENAME_CHARS = {34, 60, 62, 124, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, - 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 58, 42, 63, 92, 47}; + public static final char[] ILLEGAL_FILENAME_CHARS = { 34, 60, 62, 124, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, + 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 58, 42, 63, 92, 47 }; public static final char ILLEGAL_FILENAME_CHARS_REPLACE = '_'; /** * Just copy a file + * * @param from + * source of the file * @param to + * destination file */ public static void copy(File from, File to) { if (from.getAbsolutePath().equals(to.getAbsolutePath())) { @@ -44,7 +51,10 @@ public static void copy(File from, File to) { /** * Just delete a file. If the file is a directory, it's work. - * @param file The file to delete + * + * @param file + * The file to delete + * @return true if and only if the file is successfully deleted; false otherwise */ public static boolean delete(File file) { if (file.isDirectory()) { @@ -56,11 +66,15 @@ public static boolean delete(File file) { /** * Recursively delete a directory. + * + * @param path + * Path of the directory + * @return true if and only if the directory is successfully deleted; false otherwise */ public static boolean deleteDirectory(File path) { if (path.exists()) { File[] files = path.listFiles(); - for (File file: files) { + for (File file : files) { if (file.isDirectory()) { deleteDirectory(file); } else { @@ -117,13 +131,14 @@ public static void zip(File directory, File zipFile) { } /** - * Replace all characters that are invalid in file names on Windows or Unix operating systems - * with {@link Files#ILLEGAL_FILENAME_CHARS_REPLACE} character. + * Replace all characters that are invalid in file names on Windows or Unix operating systems with + * {@link Files#ILLEGAL_FILENAME_CHARS_REPLACE} character. *

- * This method makes sure your file name can successfully be used to write new file to disk. - * Invalid characters are listed in {@link Files#ILLEGAL_FILENAME_CHARS} array. + * This method makes sure your file name can successfully be used to write new file to disk. Invalid characters are + * listed in {@link Files#ILLEGAL_FILENAME_CHARS} array. * - * @param fileName File name to sanitize + * @param fileName + * File name to sanitize * @return Sanitized file name (new String object) if found invalid characters or same string if not */ public static String sanitizeFileName(String fileName) { @@ -131,14 +146,16 @@ public static String sanitizeFileName(String fileName) { } /** - * Replace all characters that are invalid in file names on Windows or Unix operating systems - * with passed in character. + * Replace all characters that are invalid in file names on Windows or Unix operating systems with passed in + * character. *

- * This method makes sure your file name can successfully be used to write new file to disk. - * Invalid characters are listed in {@link Files#ILLEGAL_FILENAME_CHARS} array. + * This method makes sure your file name can successfully be used to write new file to disk. Invalid characters are + * listed in {@link Files#ILLEGAL_FILENAME_CHARS} array. * - * @param fileName File name to sanitize - * @param replacement character to use as replacement for invalid chars + * @param fileName + * File name to sanitize + * @param replacement + * character to use as replacement for invalid chars * @return Sanitized file name (new String object) if found invalid characters or same string if not */ public static String sanitizeFileName(String fileName, char replacement) { diff --git a/framework/src/play/libs/IO.java b/framework/src/play/libs/IO.java index f8af0e8fcd..cb09da0ff7 100644 --- a/framework/src/play/libs/IO.java +++ b/framework/src/play/libs/IO.java @@ -1,15 +1,21 @@ package play.libs; -import org.apache.commons.io.FileUtils; -import org.apache.commons.io.IOUtils; -import play.exceptions.UnexpectedException; -import play.utils.OrderSafeProperties; +import static org.apache.commons.io.IOUtils.closeQuietly; -import java.io.*; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; import java.util.List; import java.util.Properties; -import static org.apache.commons.io.IOUtils.closeQuietly; +import org.apache.commons.io.FileUtils; +import org.apache.commons.io.IOUtils; + +import play.exceptions.UnexpectedException; +import play.utils.OrderSafeProperties; /** * IO utils @@ -18,7 +24,9 @@ public class IO { /** * Read a properties file with the utf-8 encoding - * @param is Stream to properties file + * + * @param is + * Stream to properties file * @return The Properties object */ public static Properties readUtf8Properties(InputStream is) { @@ -28,15 +36,16 @@ public static Properties readUtf8Properties(InputStream is) { return properties; } catch (Exception e) { throw new RuntimeException(e); - } - finally { + } finally { closeQuietly(is); } } /** * Read the Stream content as a string (use utf-8) - * @param is The stream to read + * + * @param is + * The stream to read * @return The String content */ public static String readContentAsString(InputStream is) { @@ -45,7 +54,11 @@ public static String readContentAsString(InputStream is) { /** * Read the Stream content as a string - * @param is The stream to read + * + * @param is + * The stream to read + * @param encoding + * Encoding to used * @return The String content */ public static String readContentAsString(InputStream is, String encoding) { @@ -55,9 +68,12 @@ public static String readContentAsString(InputStream is, String encoding) { throw new RuntimeException(e); } } + /** * Read file content to a String (always use utf-8) - * @param file The file to read + * + * @param file + * The file to read * @return The String content */ public static String readContentAsString(File file) { @@ -66,7 +82,11 @@ public static String readContentAsString(File file) { /** * Read file content to a String - * @param file The file to read + * + * @param file + * The file to read + * @param encoding + * Encoding to used * @return The String content */ public static String readContentAsString(File file, String encoding) { @@ -101,7 +121,9 @@ public static List readLines(File file) { /** * Read binary content of a file (warning does not use on large file !) - * @param file The file te read + * + * @param file + * The file te read * @return The binary data */ public static byte[] readContent(File file) { @@ -114,7 +136,9 @@ public static byte[] readContent(File file) { /** * Read binary content of a stream (warning does not use on large file !) - * @param is The stream to read + * + * @param is + * The stream to read * @return The binary data */ public static byte[] readContent(InputStream is) { @@ -127,8 +151,11 @@ public static byte[] readContent(InputStream is) { /** * Write String content to a stream (always use utf-8) - * @param content The content to write - * @param os The stream to write + * + * @param content + * The content to write + * @param os + * The stream to write */ public static void writeContent(CharSequence content, OutputStream os) { writeContent(content, os, "utf-8"); @@ -136,8 +163,13 @@ public static void writeContent(CharSequence content, OutputStream os) { /** * Write String content to a stream (always use utf-8) - * @param content The content to write - * @param os The stream to write + * + * @param content + * The content to write + * @param os + * The stream to write + * @param encoding + * Encoding to used */ public static void writeContent(CharSequence content, OutputStream os, String encoding) { try { @@ -151,8 +183,11 @@ public static void writeContent(CharSequence content, OutputStream os, String en /** * Write String content to a file (always use utf-8) - * @param content The content to write - * @param file The file to write + * + * @param content + * The content to write + * @param file + * The file to write */ public static void writeContent(CharSequence content, File file) { writeContent(content, file, "utf-8"); @@ -160,8 +195,13 @@ public static void writeContent(CharSequence content, File file) { /** * Write String content to a file (always use utf-8) - * @param content The content to write - * @param file The file to write + * + * @param content + * The content to write + * @param file + * The file to write + * @param encoding + * Encoding to used */ public static void writeContent(CharSequence content, File file, String encoding) { try { @@ -173,38 +213,50 @@ public static void writeContent(CharSequence content, File file, String encoding /** * Write binary data to a file - * @param data The binary data to write - * @param file The file to write + * + * @param data + * The binary data to write + * @param file + * The file to write */ public static void write(byte[] data, File file) { try { FileUtils.writeByteArrayToFile(file, data); - } catch(IOException e) { + } catch (IOException e) { throw new UnexpectedException(e); } } /** * Copy an stream to another one. + * + * @param is + * The source stream + * @param os + * The destination stream */ public static void copy(InputStream is, OutputStream os) { try { IOUtils.copyLarge(is, os); - } catch(IOException e) { + } catch (IOException e) { throw new UnexpectedException(e); - } - finally { + } finally { closeQuietly(is); } } /** * Copy an stream to another one. + * + * @param is + * The source stream + * @param os + * The destination stream */ public static void write(InputStream is, OutputStream os) { try { IOUtils.copyLarge(is, os); - } catch(IOException e) { + } catch (IOException e) { throw new UnexpectedException(e); } finally { closeQuietly(is); @@ -212,16 +264,20 @@ public static void write(InputStream is, OutputStream os) { } } - /** + /** * Copy an stream to another one. + * + * @param is + * The source stream + * @param f + * The destination file */ public static void write(InputStream is, File f) { try { OutputStream os = new FileOutputStream(f); try { IOUtils.copyLarge(is, os); - } - finally { + } finally { closeQuietly(is); closeQuietly(os); } @@ -236,12 +292,12 @@ public static void copyDirectory(File source, File target) { if (!target.exists()) { target.mkdir(); } - for (String child: source.list()) { + for (String child : source.list()) { copyDirectory(new File(source, child), new File(target, child)); } } else { try { - write(new FileInputStream(source), new FileOutputStream(target)); + write(new FileInputStream(source), new FileOutputStream(target)); } catch (IOException e) { throw new UnexpectedException(e); } diff --git a/framework/src/play/libs/Images.java b/framework/src/play/libs/Images.java index 270124f19f..fa501f2255 100644 --- a/framework/src/play/libs/Images.java +++ b/framework/src/play/libs/Images.java @@ -61,14 +61,11 @@ public static void resize(File originalImage, File to, int w, int h) { * @param to * The destination file * @param w - * The new width (or -1 to proportionally resize) or the maxWidth - * if keepRatio is true + * The new width (or -1 to proportionally resize) or the maxWidth if keepRatio is true * @param h - * The new height (or -1 to proportionally resize) or the - * maxHeight if keepRatio is true + * The new height (or -1 to proportionally resize) or the maxHeight if keepRatio is true * @param keepRatio - * : if true, resize will keep the original image ratio and use w - * and h as max dimensions + * if true, resize will keep the original image ratio and use w and h as max dimensions */ public static void resize(File originalImage, File to, int w, int h, boolean keepRatio) { try { @@ -204,6 +201,7 @@ public static void crop(File originalImage, File to, int x1, int y1, int x2, int * The image file * @return The base64 encoded value * @throws java.io.IOException + * Thrown if the encoding encounters any problems. */ public static String toBase64(File image) throws IOException { return "data:" + MimeTypes.getMimeType(image.getName()) + ";base64," + Codec.encodeBASE64(IO.readContent(image)); @@ -211,6 +209,12 @@ public static String toBase64(File image) throws IOException { /** * Create a captche image + * + * @param width + * The width of the captche + * @param height + * The height of the captche + * @return The given captcha */ public static Captcha captcha(int width, int height) { return new Captcha(width, height); @@ -218,6 +222,8 @@ public static Captcha captcha(int width, int height) { /** * Create a 150x150 captcha image + * + * @return The given captcha */ public static Captcha captcha() { return captcha(150, 50); @@ -236,6 +242,8 @@ public static class Captcha extends InputStream { public int w, h; public Color noise = null; + ByteArrayInputStream bais = null; + public Captcha(int w, int h) { this.w = w; this.h = h; @@ -245,14 +253,19 @@ public Captcha(int w, int h) { /** * Tell the captche to draw a text and retrieve it + * + * @return the given text */ public String getText() { return getText(5); } /** - * Tell the captche to draw a text using the specified color (ex. - * #000000) and retrieve it + * Tell the captche to draw a text using the specified color (ex. #000000) and retrieve it + * + * @param color + * a String that represents an opaque color as a 24-bit integer + * @return The text to draw */ public String getText(String color) { this.textColor = Color.decode(color); @@ -261,20 +274,38 @@ public String getText(String color) { /** * Tell the captche to draw a text of the specified size and retrieve it + * + * @param length + * the specified size of the text + * @return The text to draw */ public String getText(int length) { return getText(length, "abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789"); } /** - * Tell the captche to draw a text of the specified size using the - * specified color (ex. #000000) and retrieve it + * Tell the captche to draw a text of the specified size using the specified color (ex. #000000) and retrieve it + * + * @param color + * a String that represents an opaque color as a 24-bit integer + * @param length + * the specified size of the text + * @return The text to draw */ public String getText(String color, int length) { this.textColor = Color.decode(color); return getText(length); } + /** + * Tell the captche to draw a text of the specified size using specials characters and retrieve it + * + * @param length + * the specified size of the text + * @param chars + * List of allowed characters + * @return The text to draw + */ public String getText(int length, String chars) { char[] charsArray = chars.toCharArray(); Random random = new Random(System.currentTimeMillis()); @@ -286,6 +317,18 @@ public String getText(int length, String chars) { return text; } + /** + * Tell the captche to draw a text of the specified size using specials characters and a the specified color + * (ex. #000000)and retrieve it + * + * @param color + * a String that represents an opaque color as a 24-bit integer + * @param length + * the specified size of the text + * @param chars + * List of allowed characters + * @return The text to draw + */ public String getText(String color, int length, String chars) { this.textColor = Color.decode(color); return getText(length, chars); @@ -293,6 +336,8 @@ public String getText(String color, int length, String chars) { /** * Add noise to the captcha. + * + * @return The given captcha */ public Captcha addNoise() { noise = Color.BLACK; @@ -301,6 +346,10 @@ public Captcha addNoise() { /** * Add noise to the captcha. + * + * @param color + * a String that represents an opaque color as a 24-bit integer + * @return The given captcha */ public Captcha addNoise(String color) { noise = Color.decode(color); @@ -309,6 +358,12 @@ public Captcha addNoise(String color) { /** * Set a gradient background. + * + * @param from + * a String that represents an opaque color use to start the gradient + * @param to + * a String that represents an opaque color use to end the gradient + * @return The given captcha */ public Captcha setBackground(String from, String to) { GradiatedBackgroundProducer bg = new GradiatedBackgroundProducer(); @@ -320,6 +375,10 @@ public Captcha setBackground(String from, String to) { /** * Set a solid background. + * + * @param color + * a String that represents an opaque color as a 24-bit integer + * @return The given captcha */ public Captcha setBackground(String color) { background = new FlatColorBackgroundProducer(Color.decode(color)); @@ -328,14 +387,14 @@ public Captcha setBackground(String color) { /** * Set a squiggles background + * + * @return The given captcha */ public Captcha setSquigglesBackground() { background = new SquigglesBackgroundProducer(); return this; } // ~~ rendering - ByteArrayInputStream bais = null; - @Override public int read() throws IOException { check(); diff --git a/framework/src/play/libs/Mail.java b/framework/src/play/libs/Mail.java index 80d374a154..4f46cfcb2b 100644 --- a/framework/src/play/libs/Mail.java +++ b/framework/src/play/libs/Mail.java @@ -1,8 +1,22 @@ package play.libs; +import java.util.Date; +import java.util.Map; +import java.util.Properties; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; + +import javax.mail.Authenticator; +import javax.mail.PasswordAuthentication; +import javax.mail.Session; + import org.apache.commons.lang.StringUtils; import org.apache.commons.mail.Email; import org.apache.commons.mail.EmailException; + import play.Logger; import play.Play; import play.exceptions.MailException; @@ -11,21 +25,12 @@ import play.libs.mail.test.LegacyMockMailSystem; import play.utils.Utils.Maps; -import javax.mail.Authenticator; -import javax.mail.PasswordAuthentication; -import javax.mail.Session; -import java.util.Date; -import java.util.Map; -import java.util.Properties; -import java.util.concurrent.*; - /** * Mail utils */ public class Mail { - private static class StaticMailSystemFactory extends - AbstractMailSystemFactory { + private static class StaticMailSystemFactory extends AbstractMailSystemFactory { private final MailSystem mailSystem; @@ -40,12 +45,16 @@ public MailSystem currentMailSystem() { } - public static Session session; - public static boolean asynchronousSend = true; + public static Session session; + public static boolean asynchronousSend = true; protected static AbstractMailSystemFactory mailSystemFactory = AbstractMailSystemFactory.DEFAULT; /** * Send an email + * + * @param email + * An Email message + * @return true if email successfully send */ public static Future send(Email email) { try { @@ -62,11 +71,13 @@ protected static MailSystem currentMailSystem() { } /** - * Through this method you can substitute the current MailSystem. This is - * especially helpful for testing purposes like using mock libraries. + * Through this method you can substitute the current MailSystem. This is especially helpful for testing purposes + * like using mock libraries. * * @author Andreas Simon <a.simon@quagilis.de> - * @see MailSystem + * @param mailSystem + * The mailSystem to use + * @see MailSystem */ public static void useMailSystem(MailSystem mailSystem) { mailSystemFactory = new StaticMailSystemFactory(mailSystem); @@ -77,17 +88,15 @@ public static void resetMailSystem() { } public static Email buildMessage(Email email) throws EmailException { - String from = Play.configuration.getProperty("mail.smtp.from"); if (email.getFromAddress() == null && !StringUtils.isEmpty(from)) { email.setFrom(from); } else if (email.getFromAddress() == null) { throw new MailException("Please define a 'from' email address", new NullPointerException()); } - if ((email.getToAddresses() == null || email.getToAddresses().isEmpty()) && - (email.getCcAddresses() == null || email.getCcAddresses().isEmpty()) && - (email.getBccAddresses() == null || email.getBccAddresses().isEmpty())) - { + if ((email.getToAddresses() == null || email.getToAddresses().isEmpty()) + && (email.getCcAddresses() == null || email.getCcAddresses().isEmpty()) + && (email.getBccAddresses() == null || email.getBccAddresses().isEmpty())) { throw new MailException("Please define a recipient email address", new NullPointerException()); } if (email.getSubject() == null) { @@ -107,7 +116,8 @@ public static Session getSession() { props.put("mail.smtp.host", Play.configuration.getProperty("mail.smtp.host", "localhost")); String channelEncryption; - if (Play.configuration.containsKey("mail.smtp.protocol") && "smtps".equals(Play.configuration.getProperty("mail.smtp.protocol", "smtp"))) { + if (Play.configuration.containsKey("mail.smtp.protocol") + && "smtps".equals(Play.configuration.getProperty("mail.smtp.protocol", "smtp"))) { // Backward compatibility before stable5 channelEncryption = "starttls"; } else { @@ -117,7 +127,8 @@ public static Session getSession() { if ("clear".equals(channelEncryption)) { props.put("mail.smtp.port", "25"); } else if ("ssl".equals(channelEncryption)) { - // port 465 + setup yes ssl socket factory (won't verify that the server certificate is signed with a root ca.) + // port 465 + setup yes ssl socket factory (won't verify that the server certificate is signed with a + // root ca.) props.put("mail.smtp.port", "465"); props.put("mail.smtp.socketFactory.port", "465"); props.put("mail.smtp.socketFactory.class", "play.utils.YesSSLSocketFactory"); @@ -130,15 +141,15 @@ public static Session getSession() { // story to be continued in javamail 1.4.2 : https://glassfish.dev.java.net/issues/show_bug.cgi?id=5189 } - // Inject additional mail.* settings declared in Play! configuration + // Inject additional mail.* settings declared in Play! configuration Map additionalSettings = Maps.filterMap(Play.configuration, "^mail\\..*"); if (!additionalSettings.isEmpty()) { // Remove "password" fields additionalSettings.remove("mail.smtp.pass"); - additionalSettings.remove("mail.smtp.password"); + additionalSettings.remove("mail.smtp.password"); props.putAll(additionalSettings); } - + String user = Play.configuration.getProperty("mail.smtp.user"); String password = Play.configuration.getProperty("mail.smtp.pass"); if (password == null) { @@ -177,7 +188,9 @@ public static Session getSession() { /** * Send a JavaMail message * - * @param msg An Email message + * @param msg + * An Email message + * @return true if email successfully send */ public static Future sendMessage(final Email msg) { if (asynchronousSend) { @@ -256,7 +269,7 @@ protected PasswordAuthentication getPasswordAuthentication() { /** * Just kept for compatibility reasons, use test double substitution mechanism instead. * - * @see Mail#useMailSystem(MailSystem) + * @see Mail#useMailSystem(MailSystem) * @author Andreas Simon <a.simon@quagilis.de> */ public static LegacyMockMailSystem Mock = new LegacyMockMailSystem(); diff --git a/framework/src/play/libs/MimeTypes.java b/framework/src/play/libs/MimeTypes.java index c8a1cbf894..3670356c45 100644 --- a/framework/src/play/libs/MimeTypes.java +++ b/framework/src/play/libs/MimeTypes.java @@ -1,8 +1,5 @@ package play.libs; -import play.*; -import play.mvc.Http; - import java.io.InputStream; import java.util.Enumeration; import java.util.Map; @@ -10,6 +7,11 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; +import play.Logger; +import play.Play; +import play.PlayPlugin; +import play.mvc.Http; + /** * MimeTypes utils */ @@ -24,7 +26,9 @@ public class MimeTypes { /** * return the mimetype from a file name - * @param filename the file name + * + * @param filename + * the file name * @return the mimetype or the empty string if not found */ public static String getMimeType(String filename) { @@ -33,8 +37,11 @@ public static String getMimeType(String filename) { /** * return the mimetype from a file name.
- * @param filename the file name - * @param defaultMimeType the default mime type to return when no matching mimetype is found + * + * @param filename + * the file name + * @param defaultMimeType + * the default mime type to return when no matching mimetype is found * @return the mimetype */ public static String getMimeType(String filename, String defaultMimeType) { @@ -56,34 +63,42 @@ public static String getMimeType(String filename, String defaultMimeType) { /** * return the content-type from a file name. If none is found returning application/octet-stream
* For a text-based content-type, also return the encoding suffix eg. "text/plain; charset=utf-8" - * @param filename the file name + * + * @param filename + * the file name * @return the content-type deduced from the file extension. */ - public static String getContentType(String filename){ + public static String getContentType(String filename) { return getContentType(filename, "application/octet-stream"); } /** * return the content-type from a file name.
* For a text-based content-type, also return the encoding suffix eg. "text/plain; charset=utf-8" - * @param filename the file name - * @param defaultContentType the default content-type to return when no matching content-type is found + * + * @param filename + * the file name + * @param defaultContentType + * the default content-type to return when no matching content-type is found * @return the content-type deduced from the file extension. */ - public static String getContentType(String filename, String defaultContentType){ + public static String getContentType(String filename, String defaultContentType) { String contentType = getMimeType(filename, null); - if (contentType == null){ - contentType = defaultContentType; + if (contentType == null) { + contentType = defaultContentType; } - if (contentType != null && contentType.startsWith("text/")){ + if (contentType != null && contentType.startsWith("text/")) { return contentType + "; charset=" + getCurrentCharset(); } return contentType; } /** - * check the mimetype is referenced in the mimetypes database - * @param mimeType the mimeType to verify + * Check the mimetype is referenced in the mimetypes database + * + * @param mimeType + * the mimeType to verify + * @return true if the mimetype is referenced, false otherwise */ public static boolean isValidMimeType(String mimeType) { if (mimeType == null) { @@ -101,8 +116,7 @@ private static String getCurrentCharset() { if (currentResponse != null) { charset = currentResponse.encoding; - } - else { + } else { charset = Play.defaultWebEncoding; } @@ -110,7 +124,8 @@ private static String getCurrentCharset() { } private static synchronized void initMimetypes() { - if (mimetypes != null) return; + if (mimetypes != null) + return; // Load default mimetypes from the framework try { InputStream is = MimeTypes.class.getClassLoader().getResourceAsStream("play/libs/mime-types.properties"); @@ -120,19 +135,19 @@ private static synchronized void initMimetypes() { Logger.warn(ex.getMessage()); } // Load mimetypes from plugins - for (PlayPlugin plugin: Play.pluginCollection.getEnabledPlugins()) { + for (PlayPlugin plugin : Play.pluginCollection.getEnabledPlugins()) { Map pluginTypes = plugin.addMimeTypes(); - for (String type: pluginTypes.keySet()) { + for (String type : pluginTypes.keySet()) { mimetypes.setProperty(type, pluginTypes.get(type)); } } // Load custom mimetypes from the application configuration Enumeration confenum = Play.configuration.keys(); while (confenum.hasMoreElements()) { - String key = (String)confenum.nextElement(); + String key = (String) confenum.nextElement(); if (key.startsWith("mimetype.")) { String type = key.substring(key.indexOf('.') + 1).toLowerCase(); - String value = (String)Play.configuration.get(key); + String value = (String) Play.configuration.get(key); mimetypes.setProperty(type, value); } } diff --git a/framework/src/play/libs/OAuth.java b/framework/src/play/libs/OAuth.java index ab642de83a..59444626f7 100644 --- a/framework/src/play/libs/OAuth.java +++ b/framework/src/play/libs/OAuth.java @@ -29,7 +29,9 @@ private OAuth(ServiceInfo info) { /** * Create an OAuth object for the service described in info - * @param info must contain all information related to the service + * + * @param info + * must contain all information related to the service * @return the OAuth object */ public static OAuth service(ServiceInfo info) { @@ -42,6 +44,7 @@ public static boolean isVerifierResponse() { /** * Request the request token and secret. + * * @return a Response object holding either the result in case of a success or the error */ public Response retrieveRequestToken() { @@ -50,7 +53,9 @@ public Response retrieveRequestToken() { /** * Request the request token and secret. - * @param callbackURL the URL where the provider should redirect to + * + * @param callbackURL + * the URL where the provider should redirect to * @return a Response object holding either the result in case of a success or the error */ public Response retrieveRequestToken(String callbackURL) { @@ -65,7 +70,9 @@ public Response retrieveRequestToken(String callbackURL) { /** * Exchange a request token for an access token. - * @param requestTokenResponse a successful response obtained from retrieveRequestToken + * + * @param requestTokenResponse + * a successful response obtained from retrieveRequestToken * @return a Response object holding either the result in case of a success or the error */ public Response retrieveAccessToken(Response requestTokenResponse) { @@ -74,12 +81,15 @@ public Response retrieveAccessToken(Response requestTokenResponse) { /** * Exchange a request token for an access token. - * @param token the token obtained from a previous call - * @param secret your application secret + * + * @param token + * the token obtained from a previous call + * @param secret + * your application secret * @return a Response object holding either the result in case of a success or the error */ public Response retrieveAccessToken(String token, String secret) { - OAuthConsumer consumer = new DefaultOAuthConsumer(info.consumerKey, info.consumerSecret); + OAuthConsumer consumer = new DefaultOAuthConsumer(info.consumerKey, info.consumerSecret); consumer.setTokenWithSecret(token, secret); String verifier = Params.current().get("oauth_verifier"); try { @@ -92,6 +102,7 @@ public Response retrieveAccessToken(String token, String secret) { /** * Request the unauthorized token and secret. They can then be read with getTokens() + * * @return the url to redirect the user to get the verifier and continue the process * @deprecated use retrieveRequestToken() instead */ @@ -102,6 +113,9 @@ public TokenPair requestUnauthorizedToken() { } /** + * @param tokenPair + * The token / secret pair + * @return the url * @deprecated use retrieveAccessToken() instead */ @Deprecated @@ -111,14 +125,13 @@ public TokenPair requestAccessToken(TokenPair tokenPair) { } public String redirectUrl(String token) { - return oauth.signpost.OAuth.addQueryParameters(provider.getAuthorizationWebsiteUrl(), - oauth.signpost.OAuth.OAUTH_TOKEN, token); + return oauth.signpost.OAuth.addQueryParameters(provider.getAuthorizationWebsiteUrl(), oauth.signpost.OAuth.OAUTH_TOKEN, token); } @Deprecated public String redirectUrl(TokenPair tokenPair) { - return oauth.signpost.OAuth.addQueryParameters(provider.getAuthorizationWebsiteUrl(), - oauth.signpost.OAuth.OAUTH_TOKEN, tokenPair.token); + return oauth.signpost.OAuth.addQueryParameters(provider.getAuthorizationWebsiteUrl(), oauth.signpost.OAuth.OAUTH_TOKEN, + tokenPair.token); } /** @@ -131,11 +144,9 @@ public static class ServiceInfo { public String authorizationURL; public String consumerKey; public String consumerSecret; - public ServiceInfo(String requestTokenURL, - String accessTokenURL, - String authorizationURL, - String consumerKey, - String consumerSecret) { + + public ServiceInfo(String requestTokenURL, String accessTokenURL, String authorizationURL, String consumerKey, + String consumerSecret) { this.requestTokenURL = requestTokenURL; this.accessTokenURL = accessTokenURL; this.authorizationURL = authorizationURL; @@ -145,34 +156,39 @@ public ServiceInfo(String requestTokenURL, } /** - * Response to an OAuth 1.0 request. - * If success token and secret are non null, and error is null. - * If error token and secret are null, and error is non null. + * Response to an OAuth 1.0 request. If success token and secret are non null, and error is null. If error token and + * secret are null, and error is non null. * */ public static class Response { public final String token; public final String secret; public final Error error; + private Response(String token, String secret, Error error) { this.token = token; this.secret = secret; this.error = error; } + /** * Create a new success response - * @param pair the TokenPair returned by the provider + * + * @param pair + * the TokenPair returned by the provider * @return a new Response object holding the token pair */ private static Response success(String token, String secret) { return new Response(token, secret, null); } + private static Response error(Error error) { return new Response(null, null, error); } - @Override public String toString() { - return (error != null) ? ("Error: " + error) - : ("Success: " + token + " - " + secret); + + @Override + public String toString() { + return (error != null) ? ("Error: " + error) : ("Success: " + token + " - " + secret); } } @@ -180,13 +196,11 @@ public static class Error { public final OAuthException exception; public final Type type; public final String details; + public enum Type { - MESSAGE_SIGNER, - NOT_AUTHORIZED, - EXPECTATION_FAILED, - COMMUNICATION, - OTHER + MESSAGE_SIGNER, NOT_AUTHORIZED, EXPECTATION_FAILED, COMMUNICATION, OTHER } + private Error(OAuthException exception) { this.exception = exception; if (this.exception instanceof OAuthMessageSignerException) { @@ -202,8 +216,13 @@ private Error(OAuthException exception) { } this.details = exception.getMessage(); } - public String details() { return details; } - @Override public String toString() { + + public String details() { + return details; + } + + @Override + public String toString() { return "OAuth.Error: " + type + " - " + details; } } @@ -212,10 +231,12 @@ private Error(OAuthException exception) { public static class TokenPair { public String token; public String secret; + public TokenPair(String token, String secret) { this.token = token; this.secret = secret; } + @Override public String toString() { return token + " - " + secret; diff --git a/framework/src/play/libs/OAuth2.java b/framework/src/play/libs/OAuth2.java index 4a75a10338..85944c9028 100644 --- a/framework/src/play/libs/OAuth2.java +++ b/framework/src/play/libs/OAuth2.java @@ -4,17 +4,16 @@ import java.util.Map; import com.google.gson.JsonElement; +import com.google.gson.JsonObject; + +import play.libs.WS.HttpResponse; import play.mvc.Http.Request; import play.mvc.Scope.Params; import play.mvc.results.Redirect; -import play.libs.WS.HttpResponse; - -import com.google.gson.JsonObject; - /** - * Library to access resources protected by OAuth 2.0. For OAuth 1.0a, see play.libs.OAuth. - * See the facebook-oauth2 example for usage. + * Library to access resources protected by OAuth 2.0. For OAuth 1.0a, see play.libs.OAuth. See the facebook-oauth2 + * example for usage. */ public class OAuth2 { @@ -26,10 +25,7 @@ public class OAuth2 { public String clientid; public String secret; - public OAuth2(String authorizationURL, - String accessTokenURL, - String clientid, - String secret) { + public OAuth2(String authorizationURL, String accessTokenURL, String clientid, String secret) { this.accessTokenURL = accessTokenURL; this.authorizationURL = authorizationURL; this.clientid = clientid; @@ -44,18 +40,23 @@ public static boolean isCodeResponse() { * First step of the OAuth2 process: redirects the user to the authorisation page * * @param callbackURL + * The callback URL */ public void retrieveVerificationCode(String callbackURL) { retrieveVerificationCode(callbackURL, new HashMap()); } /** - * First step of the oAuth2 process. This redirects the user to the authorization page on the oAuth2 provider. This is a helper method that only takes one parameter name,value pair and then - * converts them into a map to be used by {@link #retrieveVerificationCode(String, Map)} + * First step of the oAuth2 process. This redirects the user to the authorization page on the oAuth2 provider. This + * is a helper method that only takes one parameter name,value pair and then converts them into a map to be used by + * {@link #retrieveVerificationCode(String, Map)} * - * @param callbackURL The URL to redirect the user to after authorization - * @param parameterName An additional parameter name - * @param parameterValue An additional parameter value + * @param callbackURL + * The URL to redirect the user to after authorization + * @param parameterName + * An additional parameter name + * @param parameterValue + * An additional parameter value */ public void retrieveVerificationCode(String callbackURL, String parameterName, String parameterValue) { Map parameters = new HashMap<>(); @@ -66,8 +67,11 @@ public void retrieveVerificationCode(String callbackURL, String parameterName, S /** * First step of the oAuth2 process. This redirects the user to the authorisation page on the oAuth2 provider. * - * @param callbackURL The URL to redirect the user to after authorisation - * @param parameters Any additional parameters that weren't included in the constructor. For example you might need to add a response_type. + * @param callbackURL + * The URL to redirect the user to after authorisation + * @param parameters + * Any additional parameters that weren't included in the constructor. For example you might need to add + * a response_type. */ public void retrieveVerificationCode(String callbackURL, Map parameters) { parameters.put(CLIENT_ID_NAME, clientid); @@ -103,6 +107,7 @@ public void requestAccessToken() { } /** + * @return The access token * @deprecated Use @{link play.libs.OAuth2.retrieveAccessToken()} instead */ @Deprecated @@ -151,9 +156,7 @@ public static class Error { public final String description; public enum Type { - COMMUNICATION, - OAUTH, - UNKNOWN + COMMUNICATION, OAUTH, UNKNOWN } private Error(Type type, String error, String description) { @@ -169,13 +172,11 @@ static Error communication() { static Error oauth2(WS.HttpResponse response) { if (response.getQueryString().containsKey("error")) { Map qs = response.getQueryString(); - return new Error(Type.OAUTH, - qs.get("error"), - qs.get("error_description")); - } else if (response.getContentType().startsWith("text/javascript")) { // Stupid Facebook returns JSON with the wrong encoding + return new Error(Type.OAUTH, qs.get("error"), qs.get("error_description")); + } else if (response.getContentType().startsWith("text/javascript")) { // Stupid Facebook returns JSON with + // the wrong encoding JsonObject jsonResponse = response.getJson().getAsJsonObject().getAsJsonObject("error"); - return new Error(Type.OAUTH, - jsonResponse.getAsJsonPrimitive("type").getAsString(), + return new Error(Type.OAUTH, jsonResponse.getAsJsonPrimitive("type").getAsString(), jsonResponse.getAsJsonPrimitive("message").getAsString()); } else { return new Error(Type.UNKNOWN, null, null); diff --git a/framework/src/play/libs/OpenID.java b/framework/src/play/libs/OpenID.java index f357497edf..8e1c612318 100644 --- a/framework/src/play/libs/OpenID.java +++ b/framework/src/play/libs/OpenID.java @@ -215,6 +215,10 @@ public static OpenID id(String id) { /** * Normalize the given openid as a standard openid + * + * @param openID + * the given openid + * @return The normalize openID */ public static String normalize(String openID) { openID = openID.trim(); @@ -239,6 +243,8 @@ public static String normalize(String openID) { /** * Is the current request an authentication response from the OP ? + * + * @return true if the current request an authentication response */ public static boolean isAuthenticationResponse() { return Params.current().get("openid.mode") != null; diff --git a/framework/src/play/libs/WS.java b/framework/src/play/libs/WS.java index d5e2033430..3712449d9a 100644 --- a/framework/src/play/libs/WS.java +++ b/framework/src/play/libs/WS.java @@ -63,16 +63,14 @@ public enum Scheme { } /** - * Singleton configured with default encoding - this one is used when - * calling static method on WS. + * Singleton configured with default encoding - this one is used when calling static method on WS. */ private static WSWithEncoding wsWithDefaultEncoding; /** - * Internal class exposing all the methods previously exposed by WS. This - * impl has information about encoding. When calling original static methods - * on WS, then a singleton of WSWithEncoding is called - configured with - * default encoding. This makes this encoding-enabling backward compatible + * Internal class exposing all the methods previously exposed by WS. This impl has information about encoding. When + * calling original static methods on WS, then a singleton of WSWithEncoding is called - configured with default + * encoding. This makes this encoding-enabling backward compatible */ public static class WSWithEncoding { public final String encoding; @@ -108,14 +106,12 @@ public String encode(String part) { } /** - * Build a WebService Request with the given URL. This object support - * chaining style programming for adding params, file, headers to - * requests. + * Build a WebService Request with the given URL. This object support chaining style programming for adding + * params, file, headers to requests. * * @param url * of the request - * @return a WSRequest on which you can add params, file headers using a - * chaining style programming. + * @return a WSRequest on which you can add params, file headers using a chaining style programming. */ public WSRequest url(String url) { init(); @@ -123,17 +119,14 @@ public WSRequest url(String url) { } /** - * Build a WebService Request with the given URL. This constructor will - * format url using params passed in arguments. This object support - * chaining style programming for adding params, file, headers to - * requests. + * Build a WebService Request with the given URL. This constructor will format url using params passed in + * arguments. This object support chaining style programming for adding params, file, headers to requests. * * @param url * to format using the given params. * @param params * the params passed to format the URL. - * @return a WSRequest on which you can add params, file headers using a - * chaining style programming. + * @return a WSRequest on which you can add params, file headers using a chaining style programming. */ public WSRequest url(String url, String... params) { Object[] encodedParams = new String[params.length]; @@ -209,29 +202,26 @@ public static String encode(String part) { } /** - * Build a WebService Request with the given URL. This object support - * chaining style programming for adding params, file, headers to requests. + * Build a WebService Request with the given URL. This object support chaining style programming for adding params, + * file, headers to requests. * * @param url * of the request - * @return a WSRequest on which you can add params, file headers using a - * chaining style programming. + * @return a WSRequest on which you can add params, file headers using a chaining style programming. */ public static WSRequest url(String url) { return wsWithDefaultEncoding.url(url); } /** - * Build a WebService Request with the given URL. This constructor will - * format url using params passed in arguments. This object support chaining - * style programming for adding params, file, headers to requests. + * Build a WebService Request with the given URL. This constructor will format url using params passed in arguments. + * This object support chaining style programming for adding params, file, headers to requests. * * @param url * to format using the given params. * @param params * the params passed to format the URL. - * @return a WSRequest on which you can add params, file headers using a - * chaining style programming. + * @return a WSRequest on which you can add params, file headers using a chaining style programming. */ public static WSRequest url(String url, String... params) { return wsWithDefaultEncoding.url(url, params); @@ -270,7 +260,7 @@ public abstract static class WSRequest { public boolean followRedirects = true; /** - * timeout: value in seconds + * Timeout: value in seconds */ public Integer timeout = 60; @@ -293,6 +283,10 @@ public WSRequest(String url, String encoding) { /** * Sets the virtual host to use in this request + * + * @param virtualHost + * The given virtual host + * @return the WSRequest */ public WSRequest withVirtualHost(String virtualHost) { this.virtualHost = virtualHost; @@ -303,6 +297,7 @@ public WSRequest withVirtualHost(String virtualHost) { * Add a MimeType to the web service request. * * @param mimeType + * the given mimeType * @return the WSRequest for chaining. */ public WSRequest mimeType(String mimeType) { @@ -311,11 +306,14 @@ public WSRequest mimeType(String mimeType) { } /** - * define client authentication for a server host provided credentials - * will be used during the request + * Define client authentication for a server host provided credentials will be used during the request * * @param username + * Login * @param password + * Password + * @param scheme + * The given Scheme * @return the WSRequest for chaining. */ public WSRequest authenticate(String username, String password, Scheme scheme) { @@ -326,11 +324,13 @@ public WSRequest authenticate(String username, String password, Scheme scheme) { } /** - * define client authentication for a server host provided credentials - * will be used during the request the basic scheme will be used + * define client authentication for a server host provided credentials will be used during the request the basic + * scheme will be used * * @param username + * Login * @param password + * Password * @return the WSRequest for chaining. */ public WSRequest authenticate(String username, String password) { @@ -338,7 +338,14 @@ public WSRequest authenticate(String username, String password) { } /** - * Sign the request for do a call to a server protected by oauth + * Sign the request for do a call to a server protected by OAuth + * + * @param oauthInfo + * OAuth Information + * @param token + * The OAuth token + * @param secret + * The secret key * * @return the WSRequest for chaining. */ @@ -357,6 +364,8 @@ public WSRequest oauth(ServiceInfo oauthInfo, OAuth.TokenPair oauthTokens) { /** * Indicate if the WS should continue when hitting a 301 or 302 * + * @param value + * Indicate if follow or not follow redirects * @return the WSRequest for chaining. */ public WSRequest followRedirects(boolean value) { @@ -365,8 +374,8 @@ public WSRequest followRedirects(boolean value) { } /** - * Set the value of the request timeout, i.e. the number of seconds - * before cutting the connection - default to 60 seconds + * Set the value of the request timeout, i.e. the number of seconds before cutting the connection - default to + * 60 seconds * * @param timeout * the timeout value, e.g. "30s", "1min" @@ -381,6 +390,7 @@ public WSRequest timeout(String timeout) { * Add files to request. This will only work with POST or PUT. * * @param files + * list of files * @return the WSRequest for chaining. */ public WSRequest files(File... files) { @@ -389,10 +399,10 @@ public WSRequest files(File... files) { } /** - * Add fileParams aka File and Name parameter to the request. This will - * only work with POST or PUT. + * Add fileParams aka File and Name parameter to the request. This will only work with POST or PUT. * * @param fileParams + * The fileParams list * @return the WSRequest for chaining. */ public WSRequest files(FileParam... fileParams) { @@ -404,6 +414,7 @@ public WSRequest files(FileParam... fileParams) { * Add the given body to the request. * * @param body + * The request body * @return the WSRequest for chaining. */ public WSRequest body(Object body) { @@ -448,6 +459,7 @@ public WSRequest setParameter(String name, Object value) { * Use the provided headers when executing request. * * @param headers + * The request headers * @return the WSRequest for chaining. */ public WSRequest headers(Map headers) { @@ -456,11 +468,13 @@ public WSRequest headers(Map headers) { } /** - * Add parameters to request. If POST or PUT, parameters are passed in - * body using x-www-form-urlencoded if alone, or form-data if there is - * files too. For any other method, those params are appended to the + * Add parameters to request. If POST or PUT, parameters are passed in body using x-www-form-urlencoded if + * alone, or form-data if there is files too. For any other method, those params are appended to the * queryString. * + * @param parameters + * The request parameters + * * @return the WSRequest for chaining. */ public WSRequest params(Map parameters) { @@ -469,11 +483,13 @@ public WSRequest params(Map parameters) { } /** - * Add parameters to request. If POST or PUT, parameters are passed in - * body using x-www-form-urlencoded if alone, or form-data if there is - * files too. For any other method, those params are appended to the + * Add parameters to request. If POST or PUT, parameters are passed in body using x-www-form-urlencoded if + * alone, or form-data if there is files too. For any other method, those params are appended to the * queryString. * + * @param parameters + * The request parameters + * * @return the WSRequest for chaining. */ public WSRequest setParameters(Map parameters) { @@ -481,66 +497,130 @@ public WSRequest setParameters(Map parameters) { return this; } - /** Execute a GET request synchronously. */ + /** + * Execute a GET request synchronously. + * + * @return The HTTP response + */ public abstract HttpResponse get(); - /** Execute a GET request asynchronously. */ + /** + * Execute a GET request asynchronously. + * + * @return The HTTP response + */ public Promise getAsync() { throw new NotImplementedException(); } - /** Execute a PATCH request. */ + /** + * Execute a PATCH request. + * + * @return The HTTP response + */ public abstract HttpResponse patch(); - /** Execute a PATCH request asynchronously. */ + /** + * Execute a PATCH request asynchronously. + * + * @return The HTTP response + */ public Promise patchAsync() { throw new NotImplementedException(); } - /** Execute a POST request. */ + /** + * Execute a POST request. + * + * @return The HTTP response + */ public abstract HttpResponse post(); - /** Execute a POST request asynchronously. */ + /** + * Execute a POST request asynchronously. + * + * @return The HTTP response + */ public Promise postAsync() { throw new NotImplementedException(); } - /** Execute a PUT request. */ + /** + * Execute a PUT request. + * + * @return The HTTP response + */ public abstract HttpResponse put(); - /** Execute a PUT request asynchronously. */ + /** + * Execute a PUT request asynchronously. + * + * @return The HTTP response + */ public Promise putAsync() { throw new NotImplementedException(); } - /** Execute a DELETE request. */ + /** + * Execute a DELETE request. + * + * @return The HTTP response + */ public abstract HttpResponse delete(); - /** Execute a DELETE request asynchronously. */ + /** + * Execute a DELETE request asynchronously. + * + * @return The HTTP response + */ public Promise deleteAsync() { throw new NotImplementedException(); } - /** Execute a OPTIONS request. */ + /** + * Execute a OPTIONS request. + * + * @return The HTTP response + */ public abstract HttpResponse options(); - /** Execute a OPTIONS request asynchronously. */ + /** + * Execute a OPTIONS request asynchronously. + * + * @return The HTTP response + */ public Promise optionsAsync() { throw new NotImplementedException(); } - /** Execute a HEAD request. */ + /** + * Execute a HEAD request. + * + * @return The HTTP response + */ public abstract HttpResponse head(); - /** Execute a HEAD request asynchronously. */ + /** + * Execute a HEAD request asynchronously. + * + * @return The HTTP response + */ public Promise headAsync() { throw new NotImplementedException(); } - /** Execute a TRACE request. */ + /** + * Execute a TRACE request. + * + * @return The HTTP response + */ public abstract HttpResponse trace(); - /** Execute a TRACE request asynchronously. */ + /** + * Execute a TRACE request asynchronously. + * + * @return The HTTP response + */ public Promise traceAsync() { throw new NotImplementedException(); } @@ -713,8 +793,7 @@ public Document getXml(String encoding) { /** * Parse the response string as a query string. * - * @return The parameters as a Map. Return an empty map if the response - * is not formed as a query string. + * @return The parameters as a Map. Return an empty map if the response is not formed as a query string. */ public Map getQueryString() { Map result = new HashMap<>(); @@ -733,8 +812,8 @@ public Map getQueryString() { /** * get the response as a stream *

- * + this method can only be called onced because async implementation - * does not allow it to be called + multiple times + + * + this method can only be called onced because async implementation does not allow it to be called + multiple + * times + *

* * @return an inputstream diff --git a/framework/src/play/libs/XML.java b/framework/src/play/libs/XML.java index b0432a1d16..496d107d35 100644 --- a/framework/src/play/libs/XML.java +++ b/framework/src/play/libs/XML.java @@ -1,6 +1,10 @@ package play.libs; -import java.io.*; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.StringReader; +import java.io.StringWriter; import java.security.Key; import java.security.Provider; import java.security.interfaces.RSAPrivateKey; @@ -67,7 +71,9 @@ public static DocumentBuilder newDocumentBuilder() { /** * Serialize to XML String - * @param document The DOM document + * + * @param document + * The DOM document * @return The XML String */ public static String serialize(Document document) { @@ -79,14 +85,16 @@ public static String serialize(Document document) { StreamResult streamResult = new StreamResult(writer); transformer.transform(domSource, streamResult); } catch (TransformerException e) { - throw new RuntimeException( - "Error when serializing XML document.", e); + throw new RuntimeException("Error when serializing XML document.", e); } return writer.toString(); } /** * Parse an XML file to DOM + * + * @param file + * The XML file * @return null if an error occurs during parsing. * */ @@ -103,6 +111,9 @@ public static Document getDocument(File file) { /** * Parse an XML string content to DOM + * + * @param xml + * The XML string * @return null if an error occurs during parsing. */ public static Document getDocument(String xml) { @@ -119,6 +130,9 @@ public static Document getDocument(String xml) { /** * Parse an XML coming from an input stream to DOM + * + * @param stream + * The XML stream * @return null if an error occurs during parsing. */ public static Document getDocument(InputStream stream) { @@ -134,12 +148,15 @@ public static Document getDocument(InputStream stream) { /** * Check the xmldsig signature of the XML document. - * @param document the document to test - * @param publicKey the public key corresponding to the key pair the document was signed with + * + * @param document + * the document to test + * @param publicKey + * the public key corresponding to the key pair the document was signed with * @return true if a correct signature is present, false otherwise */ public static boolean validSignature(Document document, Key publicKey) { - Node signatureNode = document.getElementsByTagNameNS(XMLSignature.XMLNS, "Signature").item(0); + Node signatureNode = document.getElementsByTagNameNS(XMLSignature.XMLNS, "Signature").item(0); KeySelector keySelector = KeySelector.singletonKeySelector(publicKey); try { @@ -157,9 +174,13 @@ public static boolean validSignature(Document document, Key publicKey) { /** * Sign the XML document using xmldsig. - * @param document the document to sign; it will be modified by the method. - * @param publicKey the public key from the key pair to sign the document. - * @param privateKey the private key from the key pair to sign the document. + * + * @param document + * the document to sign; it will be modified by the method. + * @param publicKey + * the public key from the key pair to sign the document. + * @param privateKey + * the private key from the key pair to sign the document. * @return the signed document for chaining. */ public static Document sign(Document document, RSAPublicKey publicKey, RSAPrivateKey privateKey) { @@ -167,16 +188,11 @@ public static Document sign(Document document, RSAPublicKey publicKey, RSAPrivat KeyInfoFactory keyInfoFactory = fac.getKeyInfoFactory(); try { - Reference ref =fac.newReference( - "", - fac.newDigestMethod(DigestMethod.SHA1, null), - Collections.singletonList(fac.newTransform(Transform.ENVELOPED, (TransformParameterSpec) null)), - null, - null); - SignedInfo si = fac.newSignedInfo(fac.newCanonicalizationMethod(CanonicalizationMethod.INCLUSIVE, - (C14NMethodParameterSpec) null), - fac.newSignatureMethod(SignatureMethod.RSA_SHA1, null), - Collections.singletonList(ref)); + Reference ref = fac.newReference("", fac.newDigestMethod(DigestMethod.SHA1, null), + Collections.singletonList(fac.newTransform(Transform.ENVELOPED, (TransformParameterSpec) null)), null, null); + SignedInfo si = fac.newSignedInfo( + fac.newCanonicalizationMethod(CanonicalizationMethod.INCLUSIVE, (C14NMethodParameterSpec) null), + fac.newSignatureMethod(SignatureMethod.RSA_SHA1, null), Collections.singletonList(ref)); DOMSignContext dsc = new DOMSignContext(privateKey, document.getDocumentElement()); KeyValue keyValue = keyInfoFactory.newKeyValue(publicKey); KeyInfo ki = keyInfoFactory.newKeyInfo(Collections.singletonList(keyValue)); diff --git a/framework/src/play/libs/XPath.java b/framework/src/play/libs/XPath.java index 26d6e61c69..dd5b414815 100644 --- a/framework/src/play/libs/XPath.java +++ b/framework/src/play/libs/XPath.java @@ -13,12 +13,16 @@ public class XPath { /** - * Select all nodes that are selected by this XPath expression. If multiple nodes match, - * multiple nodes will be returned. Nodes will be returned in document-order, + * Select all nodes that are selected by this XPath expression. If multiple nodes match, multiple nodes will be + * returned. Nodes will be returned in document-order, + * * @param path + * Path expression * @param node - * @param namespaces Namespaces that need to be available in the xpath, where the key is the - * prefix and the value the namespace URI + * The node object + * @param namespaces + * Namespaces that need to be available in the xpath, where the key is the prefix and the value the + * namespace URI * @return Nodes in document-order */ @SuppressWarnings("unchecked") @@ -31,10 +35,13 @@ public static List selectNodes(String path, Object node, Map selectNodes(String path, Object node) { @@ -59,8 +66,14 @@ public static Node selectNode(String path, Object node) { /** * Return the text of a node, or the value of an attribute - * @param path the XPath to execute - * @param node the node, node-set or Context object for evaluation. This value can be null. + * + * @param path + * the XPath to execute + * @param node + * the node, node-set or Context object for evaluation. This value can be null. + * @param namespaces + * The name spaces + * @return The text of a node */ public static String selectText(String path, Object node, Map namespaces) { try { @@ -82,8 +95,12 @@ public static String selectText(String path, Object node, Map na /** * Return the text of a node, or the value of an attribute - * @param path the XPath to execute - * @param node the node, node-set or Context object for evaluation. This value can be null. + * + * @param path + * the XPath to execute + * @param node + * the node, node-set or Context object for evaluation. This value can be null. + * @return The text of a node */ public static String selectText(String path, Object node) { return selectText(path, node, null); @@ -92,7 +109,7 @@ public static String selectText(String path, Object node) { private static DOMXPath getDOMXPath(String path, Map namespaces) throws Exception { DOMXPath xpath = new DOMXPath(path); if (namespaces != null) { - for (String prefix: namespaces.keySet()) { + for (String prefix : namespaces.keySet()) { xpath.addNamespace(prefix, namespaces.get(prefix)); } } diff --git a/framework/src/play/libs/ws/WSAsync.java b/framework/src/play/libs/ws/WSAsync.java index f2f63cb6b1..74591e23e1 100644 --- a/framework/src/play/libs/ws/WSAsync.java +++ b/framework/src/play/libs/ws/WSAsync.java @@ -1,19 +1,40 @@ package play.libs.ws; -import com.ning.http.client.*; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.UnsupportedEncodingException; +import java.net.URLDecoder; +import java.net.URLEncoder; +import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.Map; + +import javax.net.ssl.SSLContext; + +import org.apache.commons.lang.NotImplementedException; + +import com.ning.http.client.AsyncCompletionHandler; +import com.ning.http.client.AsyncHttpClient; import com.ning.http.client.AsyncHttpClient.BoundRequestBuilder; +import com.ning.http.client.AsyncHttpClientConfig; import com.ning.http.client.AsyncHttpClientConfig.Builder; +import com.ning.http.client.ProxyServer; import com.ning.http.client.Realm.AuthScheme; import com.ning.http.client.Realm.RealmBuilder; +import com.ning.http.client.Response; import com.ning.http.client.multipart.ByteArrayPart; import com.ning.http.client.multipart.FilePart; import com.ning.http.client.multipart.Part; + import oauth.signpost.AbstractOAuthConsumer; import oauth.signpost.exception.OAuthCommunicationException; import oauth.signpost.exception.OAuthExpectationFailedException; import oauth.signpost.exception.OAuthMessageSignerException; import oauth.signpost.http.HttpRequest; -import org.apache.commons.lang.NotImplementedException; import play.Logger; import play.Play; import play.libs.F.Promise; @@ -24,16 +45,6 @@ import play.libs.WS.WSRequest; import play.mvc.Http.Header; -import javax.net.ssl.SSLContext; -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.UnsupportedEncodingException; -import java.net.URLDecoder; -import java.net.URLEncoder; -import java.nio.charset.Charset; -import java.util.*; - /** * Simple HTTP client to make webservices requests. * @@ -78,7 +89,7 @@ public WSAsync() { try { proxyPortInt = Integer.parseInt(proxyPort); } catch (NumberFormatException e) { - Logger.error(e, + Logger.error(e, "Cannot parse the proxy port property '%s'. Check property http.proxyPort either in System configuration or in Play config file.", proxyPort); throw new IllegalStateException("WS proxy is misconfigured -- check the logs for details"); @@ -136,8 +147,10 @@ protected WSAsyncRequest(String url, String encoding) { } /** - * Returns the url but removed the queryString-part of it The - * QueryString-info is later added with addQueryString() + * Returns the URL but removed the queryString-part of it The QueryString-info is later added with + * addQueryString() + * + * @return The URL without the queryString-part */ protected String getUrlWithoutQueryString() { int i = url.indexOf('?'); @@ -150,6 +163,9 @@ protected String getUrlWithoutQueryString() { /** * Adds the queryString-part of the url to the BoundRequestBuilder + * + * @param requestBuilder + * : The request buider to add the queryString-part */ protected void addQueryString(BoundRequestBuilder requestBuilder) { @@ -261,7 +277,7 @@ public Promise getAsync() { return execute(prepareGet()); } - /** Execute a PATCH request.*/ + /** Execute a PATCH request. */ @Override public HttpResponse patch() { this.type = "PATCH"; @@ -272,13 +288,15 @@ public HttpResponse patch() { throw new RuntimeException(e); } } - /** Execute a PATCH request asynchronously.*/ + + /** Execute a PATCH request asynchronously. */ @Override public Promise patchAsync() { this.type = "PATCH"; sign(); return execute(preparePatch()); } + /** Execute a POST request. */ @Override public HttpResponse post() { @@ -582,9 +600,8 @@ private void checkFileBody(BoundRequestBuilder builder) { } /** - * Sets the resolved Content-type - This is added as Content-type-header - * to AHC if ser has not specified Content-type or mimeType manually - * (Cannot add it directly to this.header since this cause problem when + * Sets the resolved Content-type - This is added as Content-type-header to AHC if ser has not specified + * Content-type or mimeType manually (Cannot add it directly to this.header since this cause problem when * Request-object is used multiple times with first GET, then POST) */ private void setResolvedContentType(String contentType) { @@ -592,9 +609,8 @@ private void setResolvedContentType(String contentType) { } /** - * If generatedContentType is present AND if Content-type header is not - * already present, add generatedContentType as Content-Type to headers - * in requestBuilder + * If generatedContentType is present AND if Content-type header is not already present, add + * generatedContentType as Content-Type to headers in requestBuilder */ private void addGeneratedContentType(BoundRequestBuilder requestBuilder) { if (!headers.containsKey("Content-Type") && generatedContentType != null) { @@ -612,16 +628,17 @@ public static class HttpAsyncResponse extends HttpResponse { private Response response; /** - * you shouldnt have to create an HttpResponse yourself + * You shouldn't have to create an HttpResponse yourself * * @param response + * The given response */ public HttpAsyncResponse(Response response) { this.response = response; } /** - * the HTTP status code + * The HTTP status code * * @return the status code of the http response */ diff --git a/framework/src/play/libs/ws/WSUrlFetch.java b/framework/src/play/libs/ws/WSUrlFetch.java index 88d3248517..dc54c7eb4a 100644 --- a/framework/src/play/libs/ws/WSUrlFetch.java +++ b/framework/src/play/libs/ws/WSUrlFetch.java @@ -30,9 +30,8 @@ import play.mvc.Http.Header; /** - * Implementation of the WS interface based on Java URL Fetch API. This is to be - * used for example in Google App Engine, where the async http client can't be - * used. + * Implementation of the WS interface based on Java URL Fetch API. This is to be used for example in Google App Engine, + * where the async http client can't be used. */ public class WSUrlFetch implements WSImpl { @@ -306,6 +305,7 @@ public static class HttpUrlfetchResponse extends HttpResponse { * you shouldn't have to create an HttpResponse yourself * * @param connection + * The current connection */ public HttpUrlfetchResponse(HttpURLConnection connection) { try { diff --git a/framework/src/play/mvc/After.java b/framework/src/play/mvc/After.java index 8b7475d07f..a7c206812e 100644 --- a/framework/src/play/mvc/After.java +++ b/framework/src/play/mvc/After.java @@ -10,16 +10,26 @@ */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) -public @interface After { +public @interface After { /** * Does not intercept these actions + * + * @return List of actions not to intercept */ String[] unless() default {}; + + /** + * Only intercept these actions + * + * @return List of actions to intercept + */ String[] only() default {}; /** * Interceptor priority (0 is high priority) + * + * @return The Interceptor priority */ int priority() default 0; diff --git a/framework/src/play/mvc/Before.java b/framework/src/play/mvc/Before.java index 5e63277d07..ae60fc8386 100644 --- a/framework/src/play/mvc/Before.java +++ b/framework/src/play/mvc/Before.java @@ -14,12 +14,22 @@ /** * Does not intercept these actions + * + * @return List of actions not to intercept */ String[] unless() default {}; + + /** + * Only intercept these actions + * + * @return List of actions to intercept + */ String[] only() default {}; /** * Interceptor priority (0 is high priority) + * + * @return The Interceptor priority */ int priority() default 0; diff --git a/framework/src/play/mvc/Catch.java b/framework/src/play/mvc/Catch.java index fb9556f1df..d334163d04 100644 --- a/framework/src/play/mvc/Catch.java +++ b/framework/src/play/mvc/Catch.java @@ -10,11 +10,14 @@ */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) -public @interface Catch { +public @interface Catch { Class[] value() default {}; + /** * Interceptor priority (0 is high priority) + * + * @return The Interceptor priority */ int priority() default 0; diff --git a/framework/src/play/mvc/Controller.java b/framework/src/play/mvc/Controller.java index 5f81c9d122..7112a9d515 100644 --- a/framework/src/play/mvc/Controller.java +++ b/framework/src/play/mvc/Controller.java @@ -66,8 +66,8 @@ import play.vfs.VirtualFile; /** - * Application controller support: The controller receives input and initiates a - * response by making calls on model objects. + * Application controller support: The controller receives input and initiates a response by making calls on model + * objects. * * This is the class that your controllers should extend in most cases. */ @@ -76,115 +76,90 @@ public class Controller implements PlayController, ControllerSupport, LocalVaria /** * The current HTTP request: the message sent by the client to the server. * - * Note: The ControllersEnhancer makes sure that an appropriate thread local - * version is applied. ie : controller.request - - * controller.request.current() + * Note: The ControllersEnhancer makes sure that an appropriate thread local version is applied. ie : + * controller.request - controller.request.current() * */ protected static Http.Request request = null; /** - * The current HTTP response: The message sent back from the server after a - * request. + * The current HTTP response: The message sent back from the server after a request. * - * Note: The ControllersEnhancer makes sure that an appropriate thread local - * version is applied. ie : controller.response - - * controller.response.current() + * Note: The ControllersEnhancer makes sure that an appropriate thread local version is applied. ie : + * controller.response - controller.response.current() * */ protected static Http.Response response = null; /** - * The current HTTP session. The Play! session is not living on the server - * side but on the client side. In fact, it is stored in a signed cookie. - * This session is therefore limited to 4kb. + * The current HTTP session. The Play! session is not living on the server side but on the client side. In fact, it + * is stored in a signed cookie. This session is therefore limited to 4kb. * * From Wikipedia: * - * Client-side sessions use cookies and cryptographic techniques to maintain - * state without storing as much data on the server. When presenting a - * dynamic web page, the server sends the current state data to the client - * (web browser) in the form of a cookie. The client saves the cookie in - * memory or on disk. With each successive request, the client sends the - * cookie back to the server, and the server uses the data to "remember" the - * state of the application for that specific client and generate an - * appropriate response. This mechanism may work well in some contexts; - * however, data stored on the client is vulnerable to tampering by the user - * or by software that has access to the client computer. To use client-side - * sessions where confidentiality and integrity are required, the following - * must be guaranteed: Confidentiality: Nothing apart from the server should - * be able to interpret session data. Data integrity: Nothing apart from the - * server should manipulate session data (accidentally or maliciously). - * Authenticity: Nothing apart from the server should be able to initiate - * valid sessions. To accomplish this, the server needs to encrypt the - * session data before sending it to the client, and modification of such - * information by any other party should be prevented via cryptographic - * means. Transmitting state back and forth with every request is only - * practical when the size of the cookie is small. In essence, client-side - * sessions trade server disk space for the extra bandwidth that each web - * request will require. Moreover, web browsers limit the number and size of - * cookies that may be stored by a web site. To improve efficiency and allow - * for more session data, the server may compress the data before creating - * the cookie, decompressing it later when the cookie is returned by the - * client. - * - * Note: The ControllersEnhancer makes sure that an appropriate thread local - * version is applied. ie : controller.session - - * controller.session.current() + * Client-side sessions use cookies and cryptographic techniques to maintain state without storing as much data on + * the server. When presenting a dynamic web page, the server sends the current state data to the client (web + * browser) in the form of a cookie. The client saves the cookie in memory or on disk. With each successive request, + * the client sends the cookie back to the server, and the server uses the data to "remember" the state of the + * application for that specific client and generate an appropriate response. This mechanism may work well in some + * contexts; however, data stored on the client is vulnerable to tampering by the user or by software that has + * access to the client computer. To use client-side sessions where confidentiality and integrity are required, the + * following must be guaranteed: Confidentiality: Nothing apart from the server should be able to interpret session + * data. Data integrity: Nothing apart from the server should manipulate session data (accidentally or maliciously). + * Authenticity: Nothing apart from the server should be able to initiate valid sessions. To accomplish this, the + * server needs to encrypt the session data before sending it to the client, and modification of such information by + * any other party should be prevented via cryptographic means. Transmitting state back and forth with every request + * is only practical when the size of the cookie is small. In essence, client-side sessions trade server disk space + * for the extra bandwidth that each web request will require. Moreover, web browsers limit the number and size of + * cookies that may be stored by a web site. To improve efficiency and allow for more session data, the server may + * compress the data before creating the cookie, decompressing it later when the cookie is returned by the client. + * + * Note: The ControllersEnhancer makes sure that an appropriate thread local version is applied. ie : + * controller.session - controller.session.current() */ protected static Scope.Session session = null; /** - * The current flash scope. The flash is a temporary storage mechanism that - * is a hash map You can store values associated with keys and later - * retrieve them. It has one special property: by default, values stored - * into the flash during the processing of a request will be available - * during the processing of the immediately following request. Once that - * second request has been processed, those values are removed automatically - * from the storage + * The current flash scope. The flash is a temporary storage mechanism that is a hash map You can store values + * associated with keys and later retrieve them. It has one special property: by default, values stored into the + * flash during the processing of a request will be available during the processing of the immediately following + * request. Once that second request has been processed, those values are removed automatically from the storage * * This scope is very useful to display messages after issuing a Redirect. * - * Note: The ControllersEnhancer makes sure that an appropriate thread local - * version is applied. ie : controller.flash - controller.flash.current() + * Note: The ControllersEnhancer makes sure that an appropriate thread local version is applied. ie : + * controller.flash - controller.flash.current() */ protected static Scope.Flash flash = null; /** - * The current HTTP params. This scope allows you to access the HTTP - * parameters supplied with the request. + * The current HTTP params. This scope allows you to access the HTTP parameters supplied with the request. * - * This is useful for example to know which submit button a user pressed on - * a form. + * This is useful for example to know which submit button a user pressed on a form. * - * Note: The ControllersEnhancer makes sure that an appropriate thread local - * version is applied. ie : controller.params - controller.params.current() + * Note: The ControllersEnhancer makes sure that an appropriate thread local version is applied. ie : + * controller.params - controller.params.current() */ protected static Scope.Params params = null; /** - * The current renderArgs scope: This is a hash map that is accessible - * during the rendering phase. It means you can access variables stored in - * this scope during the rendering phase (the template phase). + * The current renderArgs scope: This is a hash map that is accessible during the rendering phase. It means you can + * access variables stored in this scope during the rendering phase (the template phase). * - * Note: The ControllersEnhancer makes sure that an appropriate thread local - * version is applied. ie : controller.renderArgs - - * controller.renderArgs.current() + * Note: The ControllersEnhancer makes sure that an appropriate thread local version is applied. ie : + * controller.renderArgs - controller.renderArgs.current() */ protected static Scope.RenderArgs renderArgs = null; /** - * The current routeArgs scope: This is a hash map that is accessible during - * the reverse routing phase. Any variable added to this scope will be used - * for reverse routing. Useful when you have a param that you want to add to - * any route without add it explicitly to every action method. + * The current routeArgs scope: This is a hash map that is accessible during the reverse routing phase. Any variable + * added to this scope will be used for reverse routing. Useful when you have a param that you want to add to any + * route without add it explicitly to every action method. * - * Note: The ControllersEnhancer makes sure that an appropriate thread local - * version is applied. ie : controller.routeArgs - - * controller.routeArgs.current() + * Note: The ControllersEnhancer makes sure that an appropriate thread local version is applied. ie : + * controller.routeArgs - controller.routeArgs.current() */ protected static Scope.RouteArgs routeArgs = null; /** - * The current Validation object. It allows you to validate objects and to - * retrieve potential validations errors for those objects. + * The current Validation object. It allows you to validate objects and to retrieve potential validations errors for + * those objects. * - * Note: The ControllersEnhancer makes sure that an appropriate thread local - * version is applied. ie : controller.validation - - * controller.validation.current() + * Note: The ControllersEnhancer makes sure that an appropriate thread local version is applied. ie : + * controller.validation - controller.validation.current() */ protected static Validation validation = null; @@ -246,8 +221,7 @@ protected static void renderXml(Document xml) { } /** - * Return a 200 OK text/xml response. Use renderXml(Object, XStream) to - * customize the result. + * Return a 200 OK text/xml response. Use renderXml(Object, XStream) to customize the result. * * @param o * the object to serialize @@ -262,16 +236,16 @@ protected static void renderXml(Object o) { * @param o * the object to serialize * @param xstream - * the XStream object to use for serialization. See XStream's - * documentation for details about customizing the output. + * the XStream object to use for serialization. See XStream's documentation for details about customizing + * the output. */ protected static void renderXml(Object o, XStream xstream) { throw new RenderXml(o, xstream); } /** - * Return a 200 OK application/binary response. Content is fully loaded in - * memory, so it should not be used with large data. + * Return a 200 OK application/binary response. Content is fully loaded in memory, so it should not be used with + * large data. * * @param is * The stream to copy @@ -293,9 +267,8 @@ protected static void renderBinary(InputStream is, long length) { } /** - * Return a 200 OK application/binary response with content-disposition - * attachment. Content is fully loaded in memory, so it should not be used - * with large data. + * Return a 200 OK application/binary response with content-disposition attachment. Content is fully loaded in + * memory, so it should not be used with large data. * * @param is * The stream to copy @@ -307,8 +280,7 @@ protected static void renderBinary(InputStream is, String name) { } /** - * Return a 200 OK application/binary response with content-disposition - * attachment. + * Return a 200 OK application/binary response with content-disposition attachment. * * @param is * The stream to copy. Content is streamed. @@ -322,9 +294,8 @@ protected static void renderBinary(InputStream is, String name, long length) { } /** - * Return a 200 OK application/binary response with content-disposition - * attachment. Content is fully loaded in memory, so it should not be used - * with large data. + * Return a 200 OK application/binary response with content-disposition attachment. Content is fully loaded in + * memory, so it should not be used with large data. * * @param is * The stream to copy @@ -338,8 +309,7 @@ protected static void renderBinary(InputStream is, String name, boolean inline) } /** - * Return a 200 OK application/binary response with content-disposition - * attachment. + * Return a 200 OK application/binary response with content-disposition attachment. * * @param is * The stream to copy @@ -355,9 +325,8 @@ protected static void renderBinary(InputStream is, String name, long length, boo } /** - * Return a 200 OK application/binary response with content-disposition - * attachment. Content is fully loaded in memory, so it should not be used - * with large data. + * Return a 200 OK application/binary response with content-disposition attachment. Content is fully loaded in + * memory, so it should not be used with large data. * * @param is * The stream to copy @@ -373,8 +342,7 @@ protected static void renderBinary(InputStream is, String name, String contentTy } /** - * Return a 200 OK application/binary response with content-disposition - * attachment. + * Return a 200 OK application/binary response with content-disposition attachment. * * @param is * The stream to copy @@ -402,8 +370,7 @@ protected static void renderBinary(File file) { } /** - * Return a 200 OK application/binary response with content-disposition - * attachment + * Return a 200 OK application/binary response with content-disposition attachment * * @param file * The file to copy @@ -452,8 +419,7 @@ protected static void renderJSON(Object o, Type type) { * @param o * The Java object to serialize * @param adapters - * A set of GSON serializers/deserializers/instance creator to - * use + * A set of GSON serializers/deserializers/instance creator to use */ protected static void renderJSON(Object o, JsonSerializer... adapters) { throw new RenderJson(o, adapters); @@ -480,6 +446,9 @@ protected static void notModified() { /** * Send a 400 Bad request + * + * @param msg + * The message */ protected static void badRequest(String msg) { throw new BadRequest(msg); @@ -849,8 +818,7 @@ protected static void renderTemplate(String templateName, Map ar } /** - * Render the template corresponding to the action's package-class-method - * name (@see template()). + * Render the template corresponding to the action's package-class-method name (@see template()). * * @param args * The template data. @@ -876,8 +844,10 @@ protected static void render(Object... args) { } /** - * Work out the default template to load for the invoked action. E.g. - * "controllers.Pages.index" returns "views/Pages/index.html". + * Work out the default template to load for the invoked action. E.g. "controllers.Pages.index" returns + * "views/Pages/index.html". + * + * @return The template name */ protected static String template() { Request theRequest = Request.current(); @@ -894,8 +864,12 @@ protected static String template() { } /** - * Work out the default template to load for the action. E.g. - * "controllers.Pages.index" returns "views/Pages/index.html". + * Work out the default template to load for the action. E.g. "controllers.Pages.index" returns + * "views/Pages/index.html". + * + * @param templateName + * The template name to work out + * @return The template name */ protected static String template(String templateName) { Request theRequest = Request.current(); @@ -915,6 +889,8 @@ protected static String template(String templateName) { * * @param clazz * The annotation class + * @param + * The class type * @return Annotation object or null if not found */ protected static T getActionAnnotation(Class clazz) { @@ -930,6 +906,8 @@ protected static T getActionAnnotation(Class clazz) { * * @param clazz * The annotation class + * @param + * The class type * @return Annotation object or null if not found */ protected static T getControllerAnnotation(Class clazz) { @@ -944,6 +922,8 @@ protected static T getControllerAnnotation(Class clazz * * @param clazz * The annotation class + * @param + * The class type * @return Annotation object or null if not found */ protected static T getControllerInheritedAnnotation(Class clazz) { @@ -969,6 +949,10 @@ protected static Class getControllerClass() { /** * Call the parent action adding this objects to the params scope + * + * @param args + * List of parameters + * @deprecated */ @Deprecated protected static void parent(Object... args) { @@ -983,7 +967,7 @@ protected static void parent(Object... args) { } /** - * Call the parent method + * Call the parent method * @deprecated */ @Deprecated protected static void parent() { @@ -992,6 +976,10 @@ protected static void parent() { /** * Call the parent action adding this objects to the params scope + * + * @param map + * List of objects to the params scop + * @deprecated */ @Deprecated protected static void parent(Map map) { @@ -1041,11 +1029,12 @@ protected static void parent(Map map) { * Suspend the current request for a specified amount of time. * *

- * Important: The method will not resume on the line after you call - * this. The method will be called again as if there was a new HTTP request. + * Important: The method will not resume on the line after you call this. The method will be called again as + * if there was a new HTTP request. * * @param timeout * Period of time to wait, e.g. "1h" means 1 hour. + * @deprecated */ @Deprecated protected static void suspend(String timeout) { @@ -1053,15 +1042,15 @@ protected static void suspend(String timeout) { } /** - * Suspend the current request for a specified amount of time (in - * milliseconds). + * Suspend the current request for a specified amount of time (in milliseconds). * *

- * Important: The method will not resume on the line after you call - * this. The method will be called again as if there was a new HTTP request. + * Important: The method will not resume on the line after you call this. The method will be called again as + * if there was a new HTTP request. * * @param millis * Number of milliseconds to wait until trying again. + * @deprecated */ @Deprecated protected static void suspend(int millis) { @@ -1073,10 +1062,13 @@ protected static void suspend(int millis) { * Suspend this request and wait for the task completion * *

- * Important: The method will not resume on the line after you call - * this. The method will be called again as if there was a new HTTP request. - * + * Important: The method will not resume on the line after you call this. The method will be called again as + * if there was a new HTTP request. + *

+ * * @param task + * Taks to wait for + * @deprecated */ @Deprecated protected static void waitFor(Future task) { @@ -1104,14 +1096,11 @@ protected static void await(int millis) { * * If isRestoring == null, the method will try to resolve it. * - * important: when using isRestoring == null you have to KNOW that - * continuation suspend is going to happen and that this method is called - * twice for this single continuation suspend operation for this specific - * request. + * important: when using isRestoring == null you have to KNOW that continuation suspend is going to happen and that + * this method is called twice for this single continuation suspend operation for this specific request. * * @param isRestoring - * true if restoring, false if storing, and null if you don't - * know + * true if restoring, false if storing, and null if you don't know */ private static void storeOrRestoreDataStateForContinuations(Boolean isRestoring) { @@ -1222,9 +1211,8 @@ protected static T await(Future future) { } /** - * Verifies that all application-code is properly enhanced. - * "application code" is the code on the callstack after leaving - * actionInvoke into the app, and before reentering Controller.await + * Verifies that all application-code is properly enhanced. "application code" is the code on the callstack after + * leaving actionInvoke into the app, and before reentering Controller.await */ private static void verifyContinuationsEnhancement() { // only check in dev mode.. @@ -1278,16 +1266,18 @@ protected static void await(Future future, F.Action callback) { public static final ThreadLocal _currentReverse = new ThreadLocal<>(); /** - * @todo - this "Usage" example below doesn't make sense. + * @play.todo TODO - this "Usage" example below doesn't make sense. * - * Usage: + * Usage: * - * + * * ActionDefinition action = reverse(); { * Application.anyAction(anyParam, "toto"); * } * String url = action.url; * + * + * @return The ActionDefiniton */ protected static ActionDefinition reverse() { ActionDefinition actionDefinition = new ActionDefinition(); @@ -1296,8 +1286,10 @@ protected static ActionDefinition reverse() { } /** - * Register a customer template name resolver. That letter allows to override - * the way templates are resolved. + * Register a customer template name resolver. That letter allows to override the way templates are resolved. + * + * @param templateNameResolver + * The template resolver */ public static void registerTemplateNameResolver(ITemplateNameResolver templateNameResolver) { if (null != Controller.templateNameResolver) @@ -1306,12 +1298,15 @@ public static void registerTemplateNameResolver(ITemplateNameResolver templateNa } /** - * This allow people that implements their own template engine to override - * the way template are resolved. + * This allow people that implements their own template engine to override the way template are resolved. */ public interface ITemplateNameResolver { /** * Return the template path given a template name. + * + * @param templateName + * The template name + * @return The template path */ String resolveTemplateName(String templateName); } diff --git a/framework/src/play/mvc/CookieDataCodec.java b/framework/src/play/mvc/CookieDataCodec.java index bf71992d43..d1a4a7ab67 100644 --- a/framework/src/play/mvc/CookieDataCodec.java +++ b/framework/src/play/mvc/CookieDataCodec.java @@ -12,17 +12,22 @@ */ public class CookieDataCodec { - /** + /** * Cookie session parser for cookie created by version 1.2.5 or before. - *

We need it to support old Play 1.2.5 session data encoding so that the cookie data doesn't become invalid when - * applications are upgraded to a newer version of Play

+ *

+ * We need it to support old Play 1.2.5 session data encoding so that the cookie data doesn't become invalid when + * applications are upgraded to a newer version of Play + *

*/ public static Pattern oldCookieSessionParser = Pattern.compile("\u0000([^:]*):([^\u0000]*)\u0000"); /** - * @param map the map to decode data into. - * @param data the data to decode. + * @param map + * the map to decode data into. + * @param data + * the data to decode. * @throws UnsupportedEncodingException + * if the encoding is not supported */ public static void decode(Map map, String data) throws UnsupportedEncodingException { // support old Play 1.2.5 session data encoding so that the cookie data doesn't become invalid when @@ -46,18 +51,18 @@ public static void decode(Map map, String data) throws Unsupport } /** - * @param map the data to encode. + * @param map + * the data to encode. * @return the encoded data. * @throws UnsupportedEncodingException + * if the encoding is not supported */ public static String encode(Map map) throws UnsupportedEncodingException { StringBuilder data = new StringBuilder(); String separator = ""; for (Map.Entry entry : map.entrySet()) { if (entry.getValue() != null) { - data.append(separator) - .append(URLEncoder.encode(entry.getKey(), "utf-8")) - .append("=") + data.append(separator).append(URLEncoder.encode(entry.getKey(), "utf-8")).append("=") .append(URLEncoder.encode(entry.getValue(), "utf-8")); separator = "&"; } @@ -67,6 +72,12 @@ public static String encode(Map map) throws UnsupportedEncodingE /** * Constant time for same length String comparison, to prevent timing attacks + * + * @param a + * The string a + * @param b + * the string b + * @return true is the 2 strings are equals */ public static boolean safeEquals(String a, String b) { if (a.length() != b.length()) { diff --git a/framework/src/play/mvc/Finally.java b/framework/src/play/mvc/Finally.java index 3bf07f3929..7b0bfd278a 100644 --- a/framework/src/play/mvc/Finally.java +++ b/framework/src/play/mvc/Finally.java @@ -10,17 +10,26 @@ */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) -public @interface Finally { +public @interface Finally { /** * Does not intercept these actions + * + * @return List of actions not to intercept */ String[] unless() default {}; + + /** + * Only intercept these actions + * + * @return List of actions to intercept + */ String[] only() default {}; /** * Interceptor priority (0 is high priority) + * + * @return The Interceptor priority */ int priority() default 0; - -} +} \ No newline at end of file diff --git a/framework/src/play/mvc/Http.java b/framework/src/play/mvc/Http.java index 63b8ff07b8..6e1e6e5d14 100644 --- a/framework/src/play/mvc/Http.java +++ b/framework/src/play/mvc/Http.java @@ -124,12 +124,10 @@ public String toString() { public static class Cookie implements Serializable { /** - * When creating cookie without specifying domain, this value is used. - * Can be configured using the property + * When creating cookie without specifying domain, this value is used. Can be configured using the property * 'application.defaultCookieDomain' in application.conf. * - * This feature can be used to allow sharing session/cookies between - * multiple sub domains. + * This feature can be used to allow sharing session/cookies between multiple sub domains. */ public static String defaultDomain = null; @@ -188,8 +186,7 @@ public static class Request implements Serializable { * URL path (excluding scheme, host and port), starting with '/'
* * Example:
- * With this full URL http://localhost:9000/path0/path1 - *
+ * With this full URL http://localhost:9000/path0/path1
* => url will be /path0/path1 */ public String url; @@ -210,8 +207,8 @@ public static class Request implements Serializable { */ public String contentType; /** - * This is the encoding used to decode this request. If encoding-info is - * not found in request, then Play.defaultWebEncoding is used + * This is the encoding used to decode this request. If encoding-info is not found in request, then + * Play.defaultWebEncoding is used */ public String encoding = Play.defaultWebEncoding; /** @@ -304,11 +301,10 @@ public static class Request implements Serializable { public final Scope.Params params = new Scope.Params(); /** - * Deprecate the default constructor to encourage the use of - * createRequest() when creating new requests. + * Deprecate the default constructor to encourage the use of createRequest() when creating new requests. * - * Cannot hide it with protected because we have to be backward - * compatible with modules - ie PlayGrizzlyAdapter.java + * Cannot hide it with protected because we have to be backward compatible with modules - ie + * PlayGrizzlyAdapter.java */ @Deprecated public Request() { @@ -317,9 +313,37 @@ public Request() { } /** - * All creation / initiating of new requests should use this method. The - * purpose of this is to "show" what is needed when creating new - * Requests. + * All creation / initiating of new requests should use this method. The purpose of this is to "show" what is + * needed when creating new Requests. + * + * @param _remoteAddress + * The remote IP address + * @param _method + * the Method + * @param _path + * path + * @param _querystring + * The query String + * @param _contentType + * The content Type + * @param _body + * The request body + * @param _url + * The request URL + * @param _host + * The request host + * @param _isLoopback + * Indicate if the request comes from loopback interface + * @param _port + * The request port + * @param _domain + * The request domain + * @param _secure + * Indicate is request is secure or not + * @param _headers + * The request headers + * @param _cookies + * The request cookies * * @return the newly created Request object */ @@ -394,8 +418,8 @@ protected void parseXForwarded() { } } - if (Play.configuration.getProperty("XForwardedOverwriteDomainAndPort", "false").toLowerCase().equals("true") && this.host != null - && !this.host.equals(_host)) { + if (Play.configuration.getProperty("XForwardedOverwriteDomainAndPort", "false").toLowerCase().equals("true") + && this.host != null && !this.host.equals(_host)) { if (this.host.contains(":")) { String[] hosts = this.host.split(":"); this.port = Integer.parseInt(hosts[1]); @@ -452,8 +476,8 @@ protected void authorizationInit() { } /** - * Automatically resolve request format from the Accept header (in this - * order : html > xml > json > text) + * Automatically resolve request format from the Accept header (in this order : html > xml > json > + * text) */ public void resolveFormat() { @@ -513,8 +537,9 @@ public Request get() { } /** - * This request was sent by an Ajax framework. (rely on the - * X-Requested-With header). + * This request was sent by an Ajax framework. (rely on the X-Requested-With header). + * + * @return True is the request is an Ajax, false otherwise */ public boolean isAjax() { if (!headers.containsKey("x-requested-with")) { @@ -541,12 +566,10 @@ public String toString() { } /** - * Return the languages requested by the browser, ordered by preference - * (preferred first). If no Accept-Language header is present, an empty - * list is returned. + * Return the languages requested by the browser, ordered by preference (preferred first). If no Accept-Language + * header is present, an empty list is returned. * - * @return Language codes in order of preference, e.g. - * "en-us,en-gb,en,de". + * @return Language codes in order of preference, e.g. "en-us,en-gb,en,de". */ public List acceptLanguage() { final Pattern qpattern = Pattern.compile("q=([0-9\\.]+)"); @@ -727,9 +750,11 @@ public void removeCookie(String name, String path) { * Set a new cookie that will expire in (current) + duration * * @param name + * the cookie name * @param value + * The cookie value * @param duration - * Ex: 3d + * the cookie duration (Ex: 3d) */ public void setCookie(String name, String value, String duration) { setCookie(name, value, null, "/", Time.parseDuration(duration), false); @@ -779,8 +804,13 @@ public void cacheFor(String duration) { /** * Add cache-control headers * + * @param etag + * the Etag value + * * @param duration - * Ex: 3h + * the cache duration (Ex: 3h) + * @param lastModified + * The last modified date */ public void cacheFor(String etag, String duration, long lastModified) { int maxAge = Time.parseDuration(duration); @@ -790,53 +820,41 @@ public void cacheFor(String etag, String duration, long lastModified) { } /** - * Add headers to allow cross-domain requests. Be careful, a lot of - * browsers don't support these features and will ignore the headers. - * Refer to the browsers' documentation to know what versions support - * them. + * Add headers to allow cross-domain requests. Be careful, a lot of browsers don't support these features and + * will ignore the headers. Refer to the browsers' documentation to know what versions support them. * * @param allowOrigin - * a comma separated list of domains allowed to perform the - * x-domain call, or "*" for all. + * a comma separated list of domains allowed to perform the x-domain call, or "*" for all. */ public void accessControl(String allowOrigin) { accessControl(allowOrigin, null, false); } /** - * Add headers to allow cross-domain requests. Be careful, a lot of - * browsers don't support these features and will ignore the headers. - * Refer to the browsers' documentation to know what versions support - * them. + * Add headers to allow cross-domain requests. Be careful, a lot of browsers don't support these features and + * will ignore the headers. Refer to the browsers' documentation to know what versions support them. * * @param allowOrigin - * a comma separated list of domains allowed to perform the - * x-domain call, or "*" for all. + * a comma separated list of domains allowed to perform the x-domain call, or "*" for all. * @param allowCredentials - * Let the browser send the cookies when doing a x-domain - * request. Only respected by the browser if allowOrigin != - * "*" + * Let the browser send the cookies when doing a x-domain request. Only respected by the browser if + * allowOrigin != "*" */ public void accessControl(String allowOrigin, boolean allowCredentials) { accessControl(allowOrigin, null, allowCredentials); } /** - * Add headers to allow cross-domain requests. Be careful, a lot of - * browsers don't support these features and will ignore the headers. - * Refer to the browsers' documentation to know what versions support - * them. + * Add headers to allow cross-domain requests. Be careful, a lot of browsers don't support these features and + * will ignore the headers. Refer to the browsers' documentation to know what versions support them. * * @param allowOrigin - * a comma separated list of domains allowed to perform the - * x-domain call, or "*" for all. + * a comma separated list of domains allowed to perform the x-domain call, or "*" for all. * @param allowMethods - * a comma separated list of HTTP methods allowed, or null - * for all. + * a comma separated list of HTTP methods allowed, or null for all. * @param allowCredentials - * Let the browser send the cookies when doing a x-domain - * request. Only respected by the browser if allowOrigin != - * "*" + * Let the browser send the cookies when doing a x-domain request. Only respected by the browser if + * allowOrigin != "*" */ public void accessControl(String allowOrigin, String allowMethods, boolean allowCredentials) { setHeader("Access-Control-Allow-Origin", allowOrigin); diff --git a/framework/src/play/mvc/Mailer.java b/framework/src/play/mvc/Mailer.java index 6e447f3b4d..5fcef74281 100644 --- a/framework/src/play/mvc/Mailer.java +++ b/framework/src/play/mvc/Mailer.java @@ -13,9 +13,18 @@ import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; +import javax.activation.DataSource; +import javax.activation.URLDataSource; +import javax.mail.internet.InternetAddress; + import org.apache.commons.lang.RandomStringUtils; import org.apache.commons.lang.StringUtils; -import org.apache.commons.mail.*; +import org.apache.commons.mail.Email; +import org.apache.commons.mail.EmailAttachment; +import org.apache.commons.mail.EmailException; +import org.apache.commons.mail.HtmlEmail; +import org.apache.commons.mail.MultiPartEmail; +import org.apache.commons.mail.SimpleEmail; import play.Logger; import play.Play; @@ -24,18 +33,14 @@ import play.exceptions.MailException; import play.exceptions.TemplateNotFoundException; import play.exceptions.UnexpectedException; +import play.libs.F; +import play.libs.F.T4; import play.libs.Mail; import play.libs.MimeTypes; import play.templates.Template; import play.templates.TemplateLoader; import play.vfs.VirtualFile; -import javax.activation.DataSource; -import javax.activation.URLDataSource; -import javax.mail.internet.InternetAddress; -import play.libs.F; -import play.libs.F.T4; - /** * Application mailer support */ @@ -45,8 +50,11 @@ public class Mailer implements LocalVariablesSupport { /** * Set subject of mail, optionally providing formatting arguments - * @param subject plain String or formatted string - interpreted as formatted string only if arguments are provided - * @param args optional arguments for formatting subject + * + * @param subject + * plain String or formatted string - interpreted as formatted string only if arguments are provided + * @param args + * optional arguments for formatting subject */ public static void setSubject(String subject, Object... args) { Map map = infos.get(); @@ -67,8 +75,13 @@ public static void addRecipient(String... recipients) { } /** - * @Deprecated use method {{@link #addRecipient(String...)}} + * Add recipients + * + * @param recipients + * List of recipients + * @deprecated use method {{@link #addRecipient(String...)}} */ + @Deprecated public static void addRecipient(Object... recipients) { List recipientList = new ArrayList<>(recipients.length); for (Object recipient : recipients) { @@ -136,8 +149,8 @@ public static void addAttachment(EmailAttachment... attachments) { infos.set(map); } - @SuppressWarnings("unchecked") - public static void attachDataSource(DataSource dataSource, String name, String description, String disposition) { + @SuppressWarnings("unchecked") + public static void attachDataSource(DataSource dataSource, String name, String description, String disposition) { Map map = infos.get(); if (map == null) { throw new UnexpectedException("Mailer not instrumented ?"); @@ -150,9 +163,9 @@ public static void attachDataSource(DataSource dataSource, String name, String d datasourceList.add(F.T4(dataSource, name, description, disposition)); infos.set(map); } - - public static void attachDataSource(DataSource dataSource, String name, String description){ - attachDataSource(dataSource, name, description, EmailAttachment.ATTACHMENT); + + public static void attachDataSource(DataSource dataSource, String name, String description) { + attachDataSource(dataSource, name, description, EmailAttachment.ATTACHMENT); } public static String attachInlineEmbed(DataSource dataSource, String name) { @@ -188,6 +201,7 @@ public static void setContentType(String contentType) { * Can be of the form xxx <m@m.com> * * @param from + * The sender name (ex: xxx <m@m.com>) */ public static void setFrom(String from) { Map map = infos.get(); @@ -197,11 +211,11 @@ public static void setFrom(String from) { map.put("from", from); infos.set(map); } - + public static void setFrom(InternetAddress from) { setFrom(from.toString()); } - + private static class InlineImage { /** content id */ private final String cid; @@ -226,7 +240,7 @@ public DataSource getDataSource() { return this.dataSource; } } - + private static class VirtualFileDataSource implements DataSource { private final VirtualFile virtualFile; @@ -273,18 +287,18 @@ public boolean equals(Object obj) { return this.virtualFile.equals(rhs.virtualFile); } } - + @Deprecated public static String getEmbedddedSrc(String urlString, String name) { return getEmbeddedSrc(urlString, name); } - + public static String getEmbeddedSrc(String urlString, String name) { Map map = infos.get(); if (map == null) { throw new UnexpectedException("Mailer not instrumented ?"); } - + DataSource dataSource; URL url = null; @@ -306,8 +320,7 @@ public static String getEmbeddedSrc(String urlString, String name) { throw new UnexpectedException("name cannot be null or empty"); } - dataSource = url.getProtocol().equals("file") ? new VirtualFileDataSource( - url.getFile()) : new URLDataSource(url); + dataSource = url.getProtocol().equals("file") ? new VirtualFileDataSource(url.getFile()) : new URLDataSource(url); } else { dataSource = new VirtualFileDataSource(img); } @@ -320,24 +333,19 @@ public static String getEmbeddedSrc(String urlString, String name) { InlineImage ii = inlineEmbeds.get(name); if (ii.getDataSource() instanceof URLDataSource) { - URLDataSource urlDataSource = (URLDataSource) ii - .getDataSource(); + URLDataSource urlDataSource = (URLDataSource) ii.getDataSource(); // Make sure the supplied URL points to the same thing // as the one already associated with this name. // NOTE: Comparing URLs with URL.equals() is a blocking // operation // in the case of a network failure therefore we use // url.toExternalForm().equals() here. - if (url == null || urlDataSource == null || !url.toExternalForm().equals( - urlDataSource.getURL().toExternalForm())) { - throw new UnexpectedException("embedded name '" + name - + "' is already bound to URL " - + urlDataSource.getURL() + if (url == null || urlDataSource == null || !url.toExternalForm().equals(urlDataSource.getURL().toExternalForm())) { + throw new UnexpectedException("embedded name '" + name + "' is already bound to URL " + urlDataSource.getURL() + "; existing names cannot be rebound"); } } else if (!ii.getDataSource().equals(dataSource)) { - throw new UnexpectedException("embedded name '" + name - + "' is already bound to URL " + dataSource.getName() + throw new UnexpectedException("embedded name '" + name + "' is already bound to URL " + dataSource.getName() + "; existing names cannot be rebound"); } @@ -345,7 +353,7 @@ public static String getEmbeddedSrc(String urlString, String name) { } // Verify that the data source is valid. - + try (InputStream is = dataSource.getInputStream()) { } catch (IOException e) { throw new UnexpectedException("Invalid URL " + urlString + " for image " + name, e); @@ -358,6 +366,7 @@ public static String getEmbeddedSrc(String urlString, String name) { * Can be of the form xxx <m@m.com> * * @param replyTo + * : The reply to address (ex: xxx <m@m.com>) */ public static void setReplyTo(String replyTo) { Map map = infos.get(); @@ -367,7 +376,7 @@ public static void setReplyTo(String replyTo) { map.put("replyTo", replyTo); infos.set(map); } - + public static void setReplyTo(InternetAddress replyTo) { setReplyTo(replyTo.toString()); } @@ -442,7 +451,7 @@ public static Future send(Object... args) { // If contentType is not specified look at the template available: // - .txt only -> text/plain // else - // - -> text/html + // - -> text/html String contentType = (String) infos.get().get("contentType"); String bodyHtml = null; String bodyText = ""; @@ -481,7 +490,8 @@ public static Future send(Object... args) { String replyTo = (String) infos.get().get("replyTo"); Email email; - if (infos.get().get("attachments") == null && infos.get().get("datasources") == null && infos.get().get("inlineEmbeds") == null ) { + if (infos.get().get("attachments") == null && infos.get().get("datasources") == null + && infos.get().get("inlineEmbeds") == null) { if (StringUtils.isEmpty(bodyHtml)) { email = new SimpleEmail(); email.setMsg(bodyText); @@ -505,7 +515,7 @@ public static Future send(Object... args) { htmlEmail.setTextMsg(bodyText); } email = htmlEmail; - + Map inlineEmbeds = (Map) infos.get().get("inlineEmbeds"); if (inlineEmbeds != null) { for (Map.Entry entry : inlineEmbeds.entrySet()) { @@ -513,7 +523,7 @@ public static Future send(Object... args) { } } } - + MultiPartEmail multiPartEmail = (MultiPartEmail) email; List objectList = (List) infos.get().get("attachments"); if (objectList != null) { @@ -523,8 +533,8 @@ public static Future send(Object... args) { } // Handle DataSource - List> datasourceList = - (List>) infos.get().get("datasources"); + List> datasourceList = (List>) infos.get() + .get("datasources"); if (datasourceList != null) { for (T4 ds : datasourceList) { multiPartEmail.attach(ds._1, ds._2, ds._3, ds._4); @@ -566,7 +576,6 @@ public static Future send(Object... args) { throw new MailException("You must specify at least one recipient."); } - List ccsList = (List) infos.get().get("ccs"); if (ccsList != null) { for (String cc : ccsList) { diff --git a/framework/src/play/mvc/Router.java b/framework/src/play/mvc/Router.java index b64d03c3dc..37bdf6d310 100644 --- a/framework/src/play/mvc/Router.java +++ b/framework/src/play/mvc/Router.java @@ -62,6 +62,15 @@ public static void load(String prefix) { /** * This one can be called to add new route. Last added is first in the route list. + * + * @param method + * The method of the route + * @param path + * The path of the route + * @param action + * The associated action + * @param headers + * The headers */ public static void prependRoute(String method, String path, String action, String headers) { prependRoute(method, path, action, null, headers); @@ -69,6 +78,13 @@ public static void prependRoute(String method, String path, String action, Strin /** * This one can be called to add new route. Last added is first in the route list. + * + * @param method + * The method of the route + * @param path + * The path of the route + * @param action + * The associated action */ public static void prependRoute(String method, String path, String action) { prependRoute(method, path, action, null, null); @@ -76,6 +92,19 @@ public static void prependRoute(String method, String path, String action) { /** * Add a route at the given position + * + * @param position + * The position where to insert the route + * @param method + * The method of the route + * @param path + * The path of the route + * @param action + * The associated action + * @param params + * The parameters + * @param headers + * The headers */ public static void addRoute(int position, String method, String path, String action, String params, String headers) { if (position > routes.size()) { @@ -86,6 +115,15 @@ public static void addRoute(int position, String method, String path, String act /** * Add a route at the given position + * + * @param position + * The position where to insert the route + * @param method + * The method of the route + * @param path + * The path of the route + * @param headers + * The headers */ public static void addRoute(int position, String method, String path, String headers) { addRoute(position, method, path, null, null, headers); @@ -93,6 +131,17 @@ public static void addRoute(int position, String method, String path, String hea /** * Add a route at the given position + * + * @param position + * The position where to insert the route + * @param method + * The method of the route + * @param path + * The path of the route + * @param action + * The associated action + * @param headers + * The headers */ public static void addRoute(int position, String method, String path, String action, String headers) { addRoute(position, method, path, action, null, headers); @@ -100,6 +149,13 @@ public static void addRoute(int position, String method, String path, String act /** * Add a new route. Will be first in the route list + * + * @param method + * The method of the route * @param action : The associated action + * @param path + * The path of the route + * @param action + * The associated action */ public static void addRoute(String method, String path, String action) { prependRoute(method, path, action); @@ -107,6 +163,15 @@ public static void addRoute(String method, String path, String action) { /** * Add a route at the given position + * + * @param method + * The method of the route + * @param path + * The path of the route + * @param action + * The associated action + * @param headers + * The headers */ public static void addRoute(String method, String path, String action, String headers) { addRoute(method, path, action, null, headers); @@ -114,6 +179,17 @@ public static void addRoute(String method, String path, String action, String he /** * Add a route + * + * @param method + * The method of the route + * @param path + * The path of the route + * @param action + * The associated action + * @param params + * The parameters + * @param headers + * The headers */ public static void addRoute(String method, String path, String action, String params, String headers) { appendRoute(method, path, action, params, headers, null, 0); @@ -122,6 +198,21 @@ public static void addRoute(String method, String path, String action, String pa /** * This is used internally when reading the route file. The order the routes are added matters and we want the * method to append the routes to the list. + * + * @param method + * The method of the route + * @param path + * The path of the route + * @param action + * The associated action + * @param params + * The parameters + * @param headers + * The headers + * @param sourceFile + * The source file + * @param line + * The source line */ public static void appendRoute(String method, String path, String action, String params, String headers, String sourceFile, int line) { routes.add(getRoute(method, path, action, params, headers, sourceFile, line)); @@ -149,6 +240,17 @@ public static Route getRoute(String method, String path, String action, String p /** * Add a new route at the beginning of the route list + * + * @param method + * The method of the route + * @param path + * The path of the route + * @param action + * The associated action + * @param params + * The parameters + * @param headers + * The headers */ public static void prependRoute(String method, String path, String action, String params, String headers) { routes.add(0, getRoute(method, path, action, params, headers)); @@ -214,11 +316,13 @@ static void parse(String content, String prefix, String fileAbsolutePath) { } /** - * In PROD mode and if the routes are already loaded, this does nothing. *

+ * In PROD mode and if the routes are already loaded, this does nothing. + *

*

* In DEV mode, this checks each routes file's "last modified" time to see if the routes need updated. - * + *

+ * * @param prefix * The prefix that the path of all routes in this route file start with. This prefix should not end with * a '/' character. @@ -634,7 +738,7 @@ public static class ActionDefinition { */ public String method; /** - * @todo - what is this? does it include the domain? + * FIXME - what is this? does it include the domain? */ public String url; /** @@ -642,11 +746,11 @@ public static class ActionDefinition { */ public boolean star; /** - * @todo - what is this? does it include the class and package? + * FIXME - what is this? does it include the class and package? */ public String action; /** - * @todo - are these the required args in the routing file, or the query string in a request? + * FIXME - are these the required args in the routing file, or the query string in a request? */ public Map args; @@ -717,7 +821,7 @@ public static class Route { public String method; public String path; /** - * @todo - what is this? + * FIXME - what is this? */ public String action; Pattern actionPattern; diff --git a/framework/src/play/mvc/Scope.java b/framework/src/play/mvc/Scope.java index 2fe30ed260..bf1b5695fc 100644 --- a/framework/src/play/mvc/Scope.java +++ b/framework/src/play/mvc/Scope.java @@ -314,8 +314,9 @@ public void clear() { } /** - * Returns true if the session is empty, e.g. does not contain anything - * else than the timestamp + * Returns true if the session is empty, e.g. does not contain anything else than the timestamp + * + * @return true if the session is empty, otherwise false */ public boolean isEmpty() { for (String key : data.keySet()) { diff --git a/framework/src/play/mvc/results/RenderBinary.java b/framework/src/play/mvc/results/RenderBinary.java index d474d03232..559c3e504d 100644 --- a/framework/src/play/mvc/results/RenderBinary.java +++ b/framework/src/play/mvc/results/RenderBinary.java @@ -1,18 +1,23 @@ package play.mvc.results; +import static org.apache.commons.io.IOUtils.closeQuietly; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.UnsupportedEncodingException; +import java.nio.charset.Charset; +import java.nio.charset.CharsetEncoder; + import org.apache.commons.codec.net.URLCodec; import org.apache.commons.io.IOUtils; + import play.exceptions.UnexpectedException; import play.libs.MimeTypes; import play.mvc.Http.Request; import play.mvc.Http.Response; -import java.io.*; -import java.nio.charset.Charset; -import java.nio.charset.CharsetEncoder; - -import static org.apache.commons.io.IOUtils.closeQuietly; - /** * 200 OK with application/octet-stream */ @@ -30,9 +35,12 @@ public class RenderBinary extends Result { private String contentType; /** - * send a binary stream as the response - * @param is the stream to read from - * @param name the name to use as Content-Disposition attachment filename + * Send a binary stream as the response + * + * @param is + * the stream to read from + * @param name + * the name to use as Content-Disposition attachment filename */ public RenderBinary(InputStream is, String name) { this(is, name, false); @@ -43,20 +51,30 @@ public RenderBinary(InputStream is, String name, long length) { } /** - * send a binary stream as the response - * @param is the stream to read from - * @param name the name to use as Content-Disposition attachment filename - * @param inline true to set the response Content-Disposition to inline + * Send a binary stream as the response + * + * @param is + * the stream to read from + * @param name + * the name to use as Content-Disposition attachment filename + * @param inline + * true to set the response Content-Disposition to inline */ public RenderBinary(InputStream is, String name, boolean inline) { this(is, name, null, inline); } /** - * send a binary stream as the response - * @param is the stream to read from - * @param name the name to use as Content-Disposition attachment filename - * @param inline true to set the response Content-Disposition to inline + * Send a binary stream as the response + * + * @param is + * the stream to read from + * @param name + * the name to use as Content-Disposition attachment filename + * @param contentType + * The content type of the stream + * @param inline + * true to set the response Content-Disposition to inline */ public RenderBinary(InputStream is, String name, String contentType, boolean inline) { this.is = is; @@ -64,7 +82,7 @@ public RenderBinary(InputStream is, String name, String contentType, boolean inl this.contentType = contentType; this.inline = inline; } - + public RenderBinary(InputStream is, String name, long length, String contentType, boolean inline) { this.is = is; this.name = name; @@ -83,26 +101,34 @@ public RenderBinary(InputStream is, String name, long length, boolean inline) { /** * Send a file as the response. Content-disposition is set to attachment. * - * @param file readable file to send back - * @param name a name to use as Content-disposition's filename + * @param file + * readable file to send back + * @param name + * a name to use as Content-disposition's filename */ public RenderBinary(File file, String name) { this(file, name, false); } /** - * Send a file as the response. - * Content-disposition is set to attachment, name is taken from file's name - * @param file readable file to send back + * Send a file as the response. Content-disposition is set to attachment, name is taken from file's name + * + * @param file + * readable file to send back */ public RenderBinary(File file) { this(file, file.getName(), true); } /** - * Send a file as the response. - * Content-disposition is set to attachment, name is taken from file's name - * @param file readable file to send back + * Send a file as the response. Content-disposition is set to attachment, name is taken from file's name + * + * @param file + * readable file to send back + * @param name + * a name to use as Content-disposition's filename + * @param inline + * true to set the response Content-Disposition to inline */ public RenderBinary(File file, String name, boolean inline) { if (file == null) { @@ -138,12 +164,10 @@ public void apply(Request request, Response response) { private void addContentDispositionHeader(Response response) throws UnsupportedEncodingException { if (name == null) { response.setHeader("Content-Disposition", dispositionType()); - } - else if (canAsciiEncode(name)) { + } else if (canAsciiEncode(name)) { String contentDisposition = "%s; filename=\"%s\""; response.setHeader("Content-Disposition", String.format(contentDisposition, dispositionType(), name)); - } - else { + } else { String encoding = getEncoding(); String contentDisposition = "%1$s; filename*=" + encoding + "''%2$s; filename=\"%2$s\""; response.setHeader("Content-Disposition", String.format(contentDisposition, dispositionType(), encoder.encode(name, encoding))); @@ -181,8 +205,7 @@ private String dispositionType() { private static void copyInputStreamAndClose(InputStream is, OutputStream out) throws IOException { try { IOUtils.copyLarge(is, out); - } - finally { + } finally { closeQuietly(is); } } diff --git a/framework/src/play/mvc/results/Result.java b/framework/src/play/mvc/results/Result.java index 04c7fd755f..7c0b3fd23b 100644 --- a/framework/src/play/mvc/results/Result.java +++ b/framework/src/play/mvc/results/Result.java @@ -24,6 +24,8 @@ protected void setContentTypeIfNotSet(Http.Response response, String contentType /** * The encoding that should be used when writing this response to the client + * + * @return The encoding of the response */ protected String getEncoding() { return Http.Response.current().encoding; diff --git a/framework/src/play/plugins/PluginCollection.java b/framework/src/play/plugins/PluginCollection.java index 8d49fba921..cb2a172800 100644 --- a/framework/src/play/plugins/PluginCollection.java +++ b/framework/src/play/plugins/PluginCollection.java @@ -44,17 +44,15 @@ * * Loading/reloading/enabling/disabling is handled here. * - * This class also exposes many PlayPlugin-methods which when called, the method - * is executed on all enabled plugins. + * This class also exposes many PlayPlugin-methods which when called, the method is executed on all enabled plugins. * - * Since all the enabled-plugins-iteration is done here, the code elsewhere is - * cleaner. + * Since all the enabled-plugins-iteration is done here, the code elsewhere is cleaner. */ public class PluginCollection { /** - * Property holding the name of the play.plugins-resource-name. Can be - * modified in unittest to supply modifies plugin-list + * Property holding the name of the play.plugins-resource-name. Can be modified in unittest to supply modifies + * plugin-list */ protected String play_plugins_resourceName = "play.plugins"; @@ -64,8 +62,8 @@ public class PluginCollection { protected List allPlugins = new ArrayList<>(); /** - * Readonly copy of allPlugins - updated each time allPlugins is updated. - * Using this cached copy so we don't have to create it all the time.. + * Readonly copy of allPlugins - updated each time allPlugins is updated. Using this cached copy so we don't have to + * create it all the time.. */ protected List allPlugins_readOnlyCopy = createReadonlyCopy(allPlugins); @@ -75,9 +73,8 @@ public class PluginCollection { protected List enabledPlugins = new ArrayList<>(); /** - * Readonly copy of enabledPlugins - updated each time enabledPlugins is - * updated. Using this cached copy so we don't have to create it all the - * time + * Readonly copy of enabledPlugins - updated each time enabledPlugins is updated. Using this cached copy so we don't + * have to create it all the time */ protected List enabledPlugins_readOnlyCopy = createReadonlyCopy(enabledPlugins); @@ -87,9 +84,8 @@ public class PluginCollection { protected List enabledPluginsWithFilters = new ArrayList<>(); /** - * Readonly copy of enabledPluginsWithFilters - updated each time - * enabledPluginsWithFilters is updated. Using this cached copy so we don't - * have to create it all the time + * Readonly copy of enabledPluginsWithFilters - updated each time enabledPluginsWithFilters is updated. Using this + * cached copy so we don't have to create it all the time */ protected List enabledPluginsWithFilters_readOnlyCopy = createReadonlyCopy(enabledPluginsWithFilters); @@ -97,6 +93,7 @@ public class PluginCollection { * Using readonly list to crash if someone tries to modify the copy. * * @param list + * The list of plugins * @return Read only list of plugins */ protected List createReadonlyCopy(List list) { @@ -239,6 +236,9 @@ public void loadPlugins() { /** * Reloads all loaded plugins that is application-supplied. + * + * @throws Exception + * If problem occurred during reload */ public void reloadApplicationPlugins() throws Exception { @@ -284,11 +284,11 @@ protected boolean isLoadedByApplicationClassloader(PlayPlugin plugin) { } /** - * Calls plugin.onLoad but detects if plugin removes other plugins from - * Play.plugins-list to detect if plugins disables a plugin the old hacked - * way.. + * Calls plugin.onLoad but detects if plugin removes other plugins from Play.plugins-list to detect if plugins + * disables a plugin the old hacked way.. * * @param plugin + * The given plugin */ @SuppressWarnings({ "deprecation" }) protected void initializePlugin(PlayPlugin plugin) { @@ -314,6 +314,7 @@ protected void initializePlugin(PlayPlugin plugin) { * Adds one plugin and enables it * * @param plugin + * The given plugin * @return true if plugin was new and was added */ protected synchronized boolean addPlugin(PlayPlugin plugin) { @@ -352,6 +353,7 @@ protected synchronized void replacePlugin(PlayPlugin oldPlugin, PlayPlugin newPl * Enable plugin. * * @param plugin + * The given plugin * @return true if plugin exists and was enabled now */ public synchronized boolean enablePlugin(PlayPlugin plugin) { @@ -381,6 +383,9 @@ public synchronized boolean enablePlugin(PlayPlugin plugin) { /** * enable plugin of specified type * + * @param pluginClazz + * The plugin class + * * @return true if plugin was enabled */ public boolean enablePlugin(Class pluginClazz) { @@ -391,6 +396,7 @@ public boolean enablePlugin(Class pluginClazz) { * Returns the first instance of a loaded plugin of specified type * * @param pluginClazz + * The plugin class * @return PlayPlugin */ public synchronized PlayPlugin getPluginInstance(Class pluginClazz) { @@ -406,6 +412,7 @@ public synchronized PlayPlugin getPluginInstance(Class plu * disable plugin * * @param plugin + * The given plugin * @return true if plugin was enabled and now is disabled */ public synchronized boolean disablePlugin(PlayPlugin plugin) { @@ -426,7 +433,10 @@ public synchronized boolean disablePlugin(PlayPlugin plugin) { } /** - * disable plugin of specified type + * Disable plugin of specified type + * + * @param pluginClazz + * The plugin class * * @return true if plugin was enabled and now is disabled */ @@ -527,8 +537,10 @@ public List getAllPlugins() { } /** - * + * Indicate if a plugin is enabled + * * @param plugin + * The given plugin * @return true if plugin is enabled */ public boolean isEnabled(PlayPlugin plugin) { diff --git a/framework/src/play/templates/GroovyTemplate.java b/framework/src/play/templates/GroovyTemplate.java index 3354255d3a..012d812263 100644 --- a/framework/src/play/templates/GroovyTemplate.java +++ b/framework/src/play/templates/GroovyTemplate.java @@ -1,24 +1,55 @@ package play.templates; -import com.jamonapi.Monitor; -import com.jamonapi.MonitorFactory; -import groovy.lang.*; +import java.io.File; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + import org.apache.commons.io.FileUtils; -import org.codehaus.groovy.control.*; +import org.codehaus.groovy.control.CompilationUnit; import org.codehaus.groovy.control.CompilationUnit.GroovyClassOperation; +import org.codehaus.groovy.control.CompilerConfiguration; +import org.codehaus.groovy.control.MultipleCompilationErrorsException; +import org.codehaus.groovy.control.Phases; +import org.codehaus.groovy.control.SourceUnit; import org.codehaus.groovy.control.messages.ExceptionMessage; import org.codehaus.groovy.control.messages.Message; import org.codehaus.groovy.control.messages.SyntaxErrorMessage; import org.codehaus.groovy.runtime.InvokerHelper; import org.codehaus.groovy.syntax.SyntaxException; import org.codehaus.groovy.tools.GroovyClass; + +import com.jamonapi.Monitor; +import com.jamonapi.MonitorFactory; + +import groovy.lang.Binding; +import groovy.lang.Closure; +import groovy.lang.GroovyClassLoader; +import groovy.lang.GroovyObjectSupport; +import groovy.lang.GroovyShell; +import groovy.lang.MissingPropertyException; +import groovy.lang.Script; import play.Logger; import play.Play; import play.Play.Mode; import play.classloading.BytecodeCache; import play.data.binding.Unbinder; -import play.exceptions.*; +import play.exceptions.ActionNotFoundException; +import play.exceptions.NoRouteFoundException; +import play.exceptions.PlayException; +import play.exceptions.TagInternalException; +import play.exceptions.TemplateCompilationException; +import play.exceptions.TemplateExecutionException; import play.exceptions.TemplateExecutionException.DoBodyException; +import play.exceptions.TemplateNotFoundException; +import play.exceptions.UnexpectedException; import play.i18n.Lang; import play.i18n.Messages; import play.libs.Codec; @@ -32,17 +63,10 @@ import play.utils.HTML; import play.utils.Java; -import java.io.File; -import java.io.PrintWriter; -import java.io.StringWriter; -import java.lang.reflect.Field; -import java.lang.reflect.Method; -import java.util.*; - public class GroovyTemplate extends BaseTemplate { static final Map safeFormatters = new HashMap<>(); - + static { safeFormatters.put("csv", new SafeCSVFormatter()); safeFormatters.put("html", new SafeHTMLFormatter()); @@ -56,7 +80,7 @@ public static void registerFormatter(String format, SafeFormatter formatter) static { new GroovyShell().evaluate("java.lang.String.metaClass.if = { condition -> if(condition) delegate; else '' }"); } - + public GroovyTemplate(String name, String source) { super(name, source); } @@ -70,7 +94,7 @@ public static class TClassLoader extends GroovyClassLoader { public TClassLoader() { super(Play.classloader); } - + public Class defineTemplate(String name, byte[] byteCode) { return defineClass(name, byteCode, 0, byteCode.length, Play.classloader.protectionDomain); } @@ -92,14 +116,14 @@ void directLoad(byte[] code) throws Exception { } } } - - protected CompilerConfiguration setUpCompilerConfiguration(){ - CompilerConfiguration compilerConfiguration = new CompilerConfiguration(); + + protected CompilerConfiguration setUpCompilerConfiguration() { + CompilerConfiguration compilerConfiguration = new CompilerConfiguration(); compilerConfiguration.setSourceEncoding("utf-8"); // ouf return compilerConfiguration; } - - protected void onCompileEnd(){ + + protected void onCompileEnd() { } @Override @@ -113,9 +137,10 @@ public void compile() { final List groovyClassesForThisTemplate = new ArrayList<>(); // ~~~ Please ! CompilerConfiguration compilerConfiguration = this.setUpCompilerConfiguration(); - + CompilationUnit compilationUnit = new CompilationUnit(compilerConfiguration); - compilationUnit.addSource(new SourceUnit(name, compiledSource, compilerConfiguration, tClassLoader, compilationUnit.getErrorCollector())); + compilationUnit.addSource( + new SourceUnit(name, compiledSource, compilerConfiguration, tClassLoader, compilationUnit.getErrorCollector())); Field phasesF = compilationUnit.getClass().getDeclaredField("phaseOperations"); phasesF.setAccessible(true); @@ -129,7 +154,7 @@ public void call(GroovyClass gclass) { } }); compilationUnit.compile(); - // ouf + // ouf // Define script classes StringBuilder sb = new StringBuilder(); @@ -152,7 +177,8 @@ public void call(GroovyClass gclass) { if (System.getProperty("precompile") != null) { try { // emit bytecode to standard class layout as well - File f = Play.getFile("precompiled/templates/" + name.replaceAll("\\{(.*)\\}", "from_$1").replace(":", "_").replace("..", "parent")); + File f = Play.getFile("precompiled/templates/" + + name.replaceAll("\\{(.*)\\}", "from_$1").replace(":", "_").replace("..", "parent")); f.getParentFile().mkdirs(); FileUtils.write(f, sb.toString(), "utf-8"); } catch (Exception e) { @@ -161,7 +187,8 @@ public void call(GroovyClass gclass) { } if (Logger.isTraceEnabled()) { - Logger.trace("%sms to compile template %s to %d classes", System.currentTimeMillis() - start, name, groovyClassesForThisTemplate.size()); + Logger.trace("%sms to compile template %s to %d classes", System.currentTimeMillis() - start, name, + groovyClassesForThisTemplate.size()); } } catch (MultipleCompilationErrorsException e) { @@ -179,18 +206,18 @@ public void call(GroovyClass gclass) { message = message.substring(0, message.lastIndexOf("@")); } throw new TemplateCompilationException(this, line, message); - } else{ - ExceptionMessage errorMessage = (ExceptionMessage ) e.getErrorCollector().getLastError(); + } else { + ExceptionMessage errorMessage = (ExceptionMessage) e.getErrorCollector().getLastError(); Exception exception = errorMessage.getCause(); Integer line = 0; String message = exception.getMessage(); - throw new TemplateCompilationException(this, line, message); + throw new TemplateCompilationException(this, line, message); } } throw new UnexpectedException(e); } catch (Exception e) { throw new UnexpectedException(e); - } finally{ + } finally { this.onCompileEnd(); } } @@ -206,20 +233,20 @@ public String render(Map args) { } } - protected Binding setUpBindingVariables(Map args){ + protected Binding setUpBindingVariables(Map args) { Binding binding = new Binding(args); binding.setVariable("play", new Play()); binding.setVariable("messages", new Messages()); binding.setVariable("lang", Lang.get()); return binding; } - + @Override protected String internalRender(Map args) { compile(); Binding binding = this.setUpBindingVariables(args); - + // If current response-object is present, add _response_encoding' Http.Response currentResponse = Http.Response.current(); if (currentResponse != null) { @@ -292,12 +319,12 @@ protected String internalRender(Map args) { // Must replace '____%LAYOUT%____' inside the string layoutR with the content from writer.. String whatToFind = "____%LAYOUT%____"; int pos = layoutR.indexOf(whatToFind); - if (pos >=0) { + if (pos >= 0) { // prepending and appending directly to writer/buffer to prevent us // from having to duplicate the string. // this makes us use half of the memory! - writer.getBuffer().insert(0,layoutR.substring(0,pos)); - writer.append(layoutR.substring(pos+whatToFind.length())); + writer.getBuffer().insert(0, layoutR.substring(0, pos)); + writer.append(layoutR.substring(pos + whatToFind.length())); return writer.toString().trim(); } return layoutR; @@ -312,15 +339,15 @@ protected String internalRender(Map args) { protected Throwable cleanStackTrace(Throwable e) { List cleanTrace = new ArrayList<>(); for (StackTraceElement se : e.getStackTrace()) { - //Here we are parsing the classname to find the file on disk the template was generated from. - //See GroovyTemplateCompiler.head() for more info. + // Here we are parsing the classname to find the file on disk the template was generated from. + // See GroovyTemplateCompiler.head() for more info. if (se.getClassName().startsWith("Template_")) { String tn = se.getClassName().substring(9); if (tn.indexOf("$") > -1) { tn = tn.substring(0, tn.indexOf("$")); } BaseTemplate template = TemplateLoader.templates.get(tn); - if( template != null ) { + if (template != null) { Integer line = template.linesMatrix.get(se.getLineNumber()); if (line != null) { String ext = ""; @@ -333,7 +360,9 @@ protected Throwable cleanStackTrace(Throwable e) { } } } - if (!se.getClassName().startsWith("org.codehaus.groovy.") && !se.getClassName().startsWith("groovy.") && !se.getClassName().startsWith("sun.reflect.") && !se.getClassName().startsWith("java.lang.reflect.") && !se.getClassName().startsWith("Template_")) { + if (!se.getClassName().startsWith("org.codehaus.groovy.") && !se.getClassName().startsWith("groovy.") + && !se.getClassName().startsWith("sun.reflect.") && !se.getClassName().startsWith("java.lang.reflect.") + && !se.getClassName().startsWith("Template_")) { cleanTrace.add(se); } } @@ -357,7 +386,7 @@ public void init(GroovyTemplate t) { extension = template.name.substring(index + 1); } } - + @Override public Object getProperty(String property) { try { @@ -376,15 +405,16 @@ public void invokeTag(Integer fromLine, String tag, Map attrs, C BaseTemplate tagTemplate = null; try { - tagTemplate = (BaseTemplate)TemplateLoader.load("tags/" + templateName + "." + callerExtension); + tagTemplate = (BaseTemplate) TemplateLoader.load("tags/" + templateName + "." + callerExtension); } catch (TemplateNotFoundException e) { try { - tagTemplate = (BaseTemplate)TemplateLoader.load("tags/" + templateName + ".tag"); + tagTemplate = (BaseTemplate) TemplateLoader.load("tags/" + templateName + ".tag"); } catch (TemplateNotFoundException ex) { if (callerExtension.equals("tag")) { throw new TemplateNotFoundException("tags/" + templateName + ".tag", template, fromLine); } - throw new TemplateNotFoundException("tags/" + templateName + "." + callerExtension + " or tags/" + templateName + ".tag", template, fromLine); + throw new TemplateNotFoundException( + "tags/" + templateName + "." + callerExtension + " or tags/" + templateName + ".tag", template, fromLine); } } TagContext.enterTag(tag); @@ -417,19 +447,27 @@ public void invokeTag(Integer fromLine, String tag, Map attrs, C } /** + * @param className + * The class name + * @return The given class + * @throws Exception + * if problem occured when loading the class * @deprecated '_' should not be used as an identifier, since it is a reserved keyword from source level 1.8 on - * use {@link #__loadClass} instead + * use {@link #__loadClass} instead */ @Deprecated public Class _(String className) throws Exception { return __loadClass(className); } - + /** * Load the class from Pay Class loader - * @param className : the class name + * + * @param className + * the class name * @return the given class * @throws Exception + * if problem occured when loading the class */ public Class __loadClass(String className) throws Exception { try { @@ -440,12 +478,15 @@ public Class __loadClass(String className) throws Exception { } /** - * This method is faster to call from groovy than __safe() since we only evaluate val.toString() - * if we need to + * This method is faster to call from groovy than __safe() since we only evaluate val.toString() if we need to + * + * @param val + * the object to evaluate + * @return The evaluating string */ public String __safeFaster(Object val) { if (val instanceof RawData) { - return ((RawData)val).data; + return ((RawData) val).data; } else if (extension != null) { SafeFormatter formatter = safeFormatters.get(extension); if (formatter != null) { @@ -456,18 +497,17 @@ public String __safeFaster(Object val) { } public String __getMessage(Object[] val) { - if (val==null) { - throw new NullPointerException("You are trying to resolve a message with an expression " + - "that is resolved to null - " + - "have you forgotten quotes around the message-key?"); + if (val == null) { + throw new NullPointerException("You are trying to resolve a message with an expression " + "that is resolved to null - " + + "have you forgotten quotes around the message-key?"); } if (val.length == 1) { return Messages.get(val[0]); } else { // extract args from val - Object[] args = new Object[val.length-1]; - for( int i=1;i)((Object[])param)[0]; + if (((Object[]) param).length == 1 && ((Object[]) param)[0] instanceof Map) { + r = (Map) ((Object[]) param)[0]; } else { // too many parameters versus action, possibly a developer error. we must warn him. if (names.length < ((Object[]) param).length) { @@ -550,13 +590,16 @@ public Object invokeMethod(String name, Object param) { } for (int i = 0; i < ((Object[]) param).length; i++) { if (((Object[]) param)[i] instanceof Router.ActionDefinition && ((Object[]) param)[i] != null) { - Unbinder.unBind(r, ((Object[]) param)[i].toString(), i < names.length ? names[i] : "", actionMethod.getAnnotations()); + Unbinder.unBind(r, ((Object[]) param)[i].toString(), i < names.length ? names[i] : "", + actionMethod.getAnnotations()); } else if (isSimpleParam(actionMethod.getParameterTypes()[i])) { if (((Object[]) param)[i] != null) { - Unbinder.unBind(r, ((Object[]) param)[i].toString(), i < names.length ? names[i] : "", actionMethod.getAnnotations()); + Unbinder.unBind(r, ((Object[]) param)[i].toString(), i < names.length ? names[i] : "", + actionMethod.getAnnotations()); } } else { - Unbinder.unBind(r, ((Object[]) param)[i], i < names.length ? names[i] : "", actionMethod.getAnnotations()); + Unbinder.unBind(r, ((Object[]) param)[i], i < names.length ? names[i] : "", + actionMethod.getAnnotations()); } } } diff --git a/framework/src/play/templates/GroovyTemplateCompiler.java b/framework/src/play/templates/GroovyTemplateCompiler.java index 5544dc243d..15513e01a9 100644 --- a/framework/src/play/templates/GroovyTemplateCompiler.java +++ b/framework/src/play/templates/GroovyTemplateCompiler.java @@ -60,6 +60,10 @@ protected String checkScalaComptability(String source) { /** * Makes the code scala compatible (for the scala module). + * + * @param source + * The string representation of the code + * @return The scala compatible source */ protected String checkScalaCompatibility(String source) { // Static access diff --git a/framework/src/play/templates/JavaExtensions.java b/framework/src/play/templates/JavaExtensions.java index dfd45bfe3c..138afbba21 100644 --- a/framework/src/play/templates/JavaExtensions.java +++ b/framework/src/play/templates/JavaExtensions.java @@ -1,9 +1,31 @@ package play.templates; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; +import java.text.DateFormat; +import java.text.DecimalFormat; +import java.text.DecimalFormatSymbols; +import java.text.Normalizer; +import java.text.NumberFormat; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Currency; +import java.util.Date; +import java.util.Iterator; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.TimeZone; + +import org.apache.commons.lang.StringEscapeUtils; + import groovy.lang.Closure; import groovy.util.XmlSlurper; import groovy.util.slurpersupport.GPathResult; -import org.apache.commons.lang.StringEscapeUtils; import play.Logger; import play.i18n.Lang; import play.i18n.Messages; @@ -12,13 +34,6 @@ import play.templates.BaseTemplate.RawData; import play.utils.HTML; -import java.io.PrintWriter; -import java.io.StringWriter; -import java.io.UnsupportedEncodingException; -import java.net.URLEncoder; -import java.text.*; -import java.util.*; - /** * Java extensions in templates */ @@ -211,7 +226,7 @@ public static String since(Date date, Boolean stopAtMonth) { public static String asdate(Long timestamp) { return asdate(timestamp, I18N.getDateFormat()); } - + public static String asdate(Long timestamp, String pattern) { return asdate(timestamp, pattern, Lang.get()); } @@ -347,7 +362,17 @@ public static String pluralize(Collection n, String[] forms) { } public static String noAccents(String string) { - return Normalizer.normalize(string, Normalizer.Form.NFKC).replaceAll("[àáâãäåāąă]", "a").replaceAll("[çćčĉċ]", "c").replaceAll("[ďđð]", "d").replaceAll("[èéêëēęěĕė]", "e").replaceAll("[ƒſ]", "f").replaceAll("[ĝğġģ]", "g").replaceAll("[ĥħ]", "h").replaceAll("[ìíîïīĩĭįı]", "i").replaceAll("[ijĵ]", "j").replaceAll("[ķĸ]", "k").replaceAll("[łľĺļŀ]", "l").replaceAll("[ñńňņʼnŋ]", "n").replaceAll("[òóôõöøōőŏœ]", "o").replaceAll("[Þþ]", "p").replaceAll("[ŕřŗ]", "r").replaceAll("[śšşŝș]", "s").replaceAll("[ťţŧț]", "t").replaceAll("[ùúûüūůűŭũų]", "u").replaceAll("[ŵ]", "w").replaceAll("[ýÿŷ]", "y").replaceAll("[žżź]", "z").replaceAll("[æ]", "ae").replaceAll("[ÀÁÂÃÄÅĀĄĂ]", "A").replaceAll("[ÇĆČĈĊ]", "C").replaceAll("[ĎĐÐ]", "D").replaceAll("[ÈÉÊËĒĘĚĔĖ]", "E").replaceAll("[ĜĞĠĢ]", "G").replaceAll("[ĤĦ]", "H").replaceAll("[ÌÍÎÏĪĨĬĮİ]", "I").replaceAll("[Ĵ]", "J").replaceAll("[Ķ]", "K").replaceAll("[ŁĽĹĻĿ]", "L").replaceAll("[ÑŃŇŅŊ]", "N").replaceAll("[ÒÓÔÕÖØŌŐŎ]", "O").replaceAll("[ŔŘŖ]", "R").replaceAll("[ŚŠŞŜȘ]", "S").replaceAll("[ÙÚÛÜŪŮŰŬŨŲ]", "U").replaceAll("[Ŵ]", "W").replaceAll("[ÝŶŸ]", "Y").replaceAll("[ŹŽŻ]", "Z").replaceAll("[ß]", "ss"); + return Normalizer.normalize(string, Normalizer.Form.NFKC).replaceAll("[àáâãäåāąă]", "a").replaceAll("[çćčĉċ]", "c") + .replaceAll("[ďđð]", "d").replaceAll("[èéêëēęěĕė]", "e").replaceAll("[ƒſ]", "f").replaceAll("[ĝğġģ]", "g") + .replaceAll("[ĥħ]", "h").replaceAll("[ìíîïīĩĭįı]", "i").replaceAll("[ijĵ]", "j").replaceAll("[ķĸ]", "k") + .replaceAll("[łľĺļŀ]", "l").replaceAll("[ñńňņʼnŋ]", "n").replaceAll("[òóôõöøōőŏœ]", "o").replaceAll("[Þþ]", "p") + .replaceAll("[ŕřŗ]", "r").replaceAll("[śšşŝș]", "s").replaceAll("[ťţŧț]", "t").replaceAll("[ùúûüūůűŭũų]", "u") + .replaceAll("[ŵ]", "w").replaceAll("[ýÿŷ]", "y").replaceAll("[žżź]", "z").replaceAll("[æ]", "ae") + .replaceAll("[ÀÁÂÃÄÅĀĄĂ]", "A").replaceAll("[ÇĆČĈĊ]", "C").replaceAll("[ĎĐÐ]", "D").replaceAll("[ÈÉÊËĒĘĚĔĖ]", "E") + .replaceAll("[ĜĞĠĢ]", "G").replaceAll("[ĤĦ]", "H").replaceAll("[ÌÍÎÏĪĨĬĮİ]", "I").replaceAll("[Ĵ]", "J") + .replaceAll("[Ķ]", "K").replaceAll("[ŁĽĹĻĿ]", "L").replaceAll("[ÑŃŇŅŊ]", "N").replaceAll("[ÒÓÔÕÖØŌŐŎ]", "O") + .replaceAll("[ŔŘŖ]", "R").replaceAll("[ŚŠŞŜȘ]", "S").replaceAll("[ÙÚÛÜŪŮŰŬŨŲ]", "U").replaceAll("[Ŵ]", "W") + .replaceAll("[ÝŶŸ]", "Y").replaceAll("[ŹŽŻ]", "Z").replaceAll("[ß]", "ss"); } public static String slugify(String string) { @@ -385,14 +410,24 @@ public static String yesno(Object o, String[] values) { /** * return the last item of a list or null if the List is null + * + * @param items + * List of items + * @return the last item of a list or null if the List is null */ public static Object last(List items) { return (items == null) ? null : items.get(items.size() - 1); } /** - * concatenate items of a collection as a string separated with separator - * items toString() method should be implemented to provide a string representation + * Concatenate items of a collection as a string separated with separator items toString() method should be + * implemented to provide a string representation + * + * @param items + * List of items + * @param separator + * The separator to used + * @return The concatenate items of a collection as a string */ public static String join(Collection items, String separator) { if (items == null) { diff --git a/framework/src/play/templates/Template.java b/framework/src/play/templates/Template.java index 6b168ec594..7a9eb09cde 100644 --- a/framework/src/play/templates/Template.java +++ b/framework/src/play/templates/Template.java @@ -12,10 +12,12 @@ public abstract class Template { /** * Starts the rendering process without modifying the args-map - * @param args map containing data binding info + * + * @param args + * map containing data binding info * @return the result of the complete rendering */ - public String render( Map args ) { + public String render(Map args) { // starts the internal recursive rendering process with // a copy of the passed args-map. This is done // to prevent us from pollution the users map with @@ -23,17 +25,19 @@ public String render( Map args ) { // // Since the original args is not polluted it can be used as input // to another rendering operation later - return internalRender(new HashMap<>(args) ); + return internalRender(new HashMap<>(args)); } - /** - * The internal rendering method - When one template calls another template, - * this method is used. The input args-map is constantly being modified, as different - * templates "communicate" with each other by storing info in the map + * The internal rendering method - When one template calls another template, this method is used. The input args-map + * is constantly being modified, as different templates "communicate" with each other by storing info in the map + * + * @param args + * List of arguments use in render + * @return The template result as string */ protected abstract String internalRender(Map args); - + public String render() { return internalRender(new HashMap()); } diff --git a/framework/src/play/templates/TemplateLoader.java b/framework/src/play/templates/TemplateLoader.java index 36409fe618..ab537d7fbd 100644 --- a/framework/src/play/templates/TemplateLoader.java +++ b/framework/src/play/templates/TemplateLoader.java @@ -1,21 +1,19 @@ package play.templates; -import java.nio.file.FileSystem; import java.nio.file.InvalidPathException; -import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.atomic.AtomicLong; -import java.util.Collections; import play.Logger; import play.Play; -import play.vfs.VirtualFile; import play.exceptions.TemplateCompilationException; import play.exceptions.TemplateNotFoundException; +import play.vfs.VirtualFile; public class TemplateLoader { @@ -23,29 +21,29 @@ public class TemplateLoader { /** * See getUniqueNumberForTemplateFile() for more info */ - private static AtomicLong nextUniqueNumber = new AtomicLong(1000);//we start on 1000 + private static AtomicLong nextUniqueNumber = new AtomicLong(1000);// we start on 1000 private static Map templateFile2UniqueNumber = Collections.synchronizedMap(new HashMap()); /** - * All loaded templates is cached in the templates-list using a key. - * This key is included as part of the classname for the generated class for a specific template. - * The key is included in the classname to make it possible to resolve the original template-file - * from the classname, when creating cleanStackTrace + * All loaded templates is cached in the templates-list using a key. This key is included as part of the classname + * for the generated class for a specific template. The key is included in the classname to make it possible to + * resolve the original template-file from the classname, when creating cleanStackTrace * * This method returns a unique representation of the path which is usable as part of a classname * * @param path + * Path of the template file * @return a unique representation of the path which is usable as part of a classname */ public static String getUniqueNumberForTemplateFile(String path) { - //a path cannot be a valid classname so we have to convert it somehow. - //If we did some encoding on the path, the result would be at least as long as the path. - //Therefor we assign a unique number to each path the first time we see it, and store it.. - //This way, all seen paths gets a unique number. This number is our UniqueValidClassnamePart.. + // a path cannot be a valid classname so we have to convert it somehow. + // If we did some encoding on the path, the result would be at least as long as the path. + // Therefor we assign a unique number to each path the first time we see it, and store it.. + // This way, all seen paths gets a unique number. This number is our UniqueValidClassnamePart.. String uniqueNumber = templateFile2UniqueNumber.get(path); if (uniqueNumber == null) { - //this is the first time we see this path - must assign a unique number to it. + // this is the first time we see this path - must assign a unique number to it. uniqueNumber = Long.toString(nextUniqueNumber.getAndIncrement()); templateFile2UniqueNumber.put(path, uniqueNumber); } @@ -54,7 +52,9 @@ public static String getUniqueNumberForTemplateFile(String path) { /** * Load a template from a virtual file - * @param file A VirtualFile + * + * @param file + * A VirtualFile * @return The executable template */ public static Template load(VirtualFile file) { @@ -69,7 +69,8 @@ public static Template load(VirtualFile file) { String key = getUniqueNumberForTemplateFile(fileRelativePath); if (!templates.containsKey(key) || templates.get(key).compiledTemplate == null) { if (Play.usePrecompiled) { - BaseTemplate template = new GroovyTemplate(fileRelativePath.replaceAll("\\{(.*)\\}", "from_$1").replace(":", "_").replace("..", "parent"), ""); + BaseTemplate template = new GroovyTemplate( + fileRelativePath.replaceAll("\\{(.*)\\}", "from_$1").replace(":", "_").replace("..", "parent"), ""); try { template.loadPrecompiled(); templates.put(key, template); @@ -98,8 +99,11 @@ public static Template load(VirtualFile file) { /** * Load a template from a String - * @param key A unique identifier for the template, used for retrieving a cached template - * @param source The template source + * + * @param key + * A unique identifier for the template, used for retrieving a cached template + * @param source + * The template source * @return A Template */ public static BaseTemplate load(String key, String source) { @@ -123,10 +127,14 @@ public static BaseTemplate load(String key, String source) { } /** - * Clean the cache for that key - * Then load a template from a String - * @param key A unique identifier for the template, used for retrieving a cached template - * @param source The template source + * Clean the cache for that key Then load a template from a String + * + * @param key + * A unique identifier for the template, used for retrieving a cached template + * @param source + * The template source + * @param reload + * : Indicate if we must clean the cache * @return A Template */ public static BaseTemplate load(String key, String source, boolean reload) { @@ -136,7 +144,9 @@ public static BaseTemplate load(String key, String source, boolean reload) { /** * Load template from a String, but don't cache it - * @param source The template source + * + * @param source + * The template source * @return A Template */ public static BaseTemplate loadString(String source) { @@ -153,7 +163,9 @@ public static void cleanCompiledCache() { /** * Cleans the specified key from the cache - * @param key The template key + * + * @param key + * The template key */ public static void cleanCompiledCache(String key) { templates.remove(key); @@ -161,7 +173,9 @@ public static void cleanCompiledCache(String key) { /** * Load a template - * @param path The path of the template (ex: Application/index.html) + * + * @param path + * The path of the template (ex: Application/index.html) * @return The executable template */ public static Template load(String path) { @@ -182,16 +196,12 @@ public static Template load(String path) { } } /* - if (template == null) { - //When using the old 'key = (file.relativePath().hashCode() + "").replace("-", "M");', - //the next line never return anything, since all values written to templates is using the - //above key. - //when using just file.relativePath() as key, the next line start returning stuff.. - //therefor I have commented it out. - template = templates.get(path); - } + * if (template == null) { //When using the old 'key = (file.relativePath().hashCode() + "").replace("-", + * "M");', //the next line never return anything, since all values written to templates is using the //above + * key. //when using just file.relativePath() as key, the next line start returning stuff.. //therefor I have + * commented it out. template = templates.get(path); } */ - //TODO: remove ? + // TODO: remove ? if (template == null) { VirtualFile tf = Play.getVirtualFile(path); if (tf != null && tf.exists()) { @@ -205,6 +215,7 @@ public static Template load(String path) { /** * List all found templates + * * @return A list of executable templates */ public static List