Congratulations by the time you have reached this section, you probably have mastered the basics of Ext-Scripting, you probably already can edit your local files and have them refreshed on the fly
Under normal circumstances you, should be set up by now and you can start coding happily. However since this is a framework based reloading mechanism it is wise to dig a little bit deeper and to know what is happening under the hood and why things behave like they do. If you are interested then read on.
Additionally to the standard reloading feature, Ext-Scripting provides two components which hopefully will make the life of every programmer easier.
- The Compiler Output Component
- The Change History Component
Note currently and for the foreseeable future only Facelets as page description language will be supported by the components.
To use the components following namespace has to be included
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:f="http://java.sun.com/jsf/core" xmlns:exs="http://myfaces.apache.org/ext-scripting" xmlns:h="http://java.sun.com/jsf/html"> <h:head>
One of the cornerstones of Ext-Scripting is the dynamic recompilation. Every file changed, is reloaded, while you hit refresh on the browser.
Now, under normal circumstances, the compiler errors and warnings are written to the console log as following:
Java Compiler, Error on line: org/apache/myfaces/javaloader/blog/Blog.java:30: class, interface, or enum expected30
Now, trying to catch those errors within the log is "mildly spoken" annoying and time consuming. Exactly for bypassing this problem a compiler output component can be used either in your page or preferably in a second page.
The following Video shows the compiler output component in action
The compiler output component currently is presented as Facelets only component as follows
<exs:compilerOutput errorsLabel="Errors:" warningsLabel="Warnings:" scriptingLanguage=""/>
Following attributes can be used
|Attribute Name||Possible Values||Description|
|errorsLabel||All values are allowed||A Label which is displayed in above all errors to notify the user that the error section starts here|
|WarningsLabel||All values are allowed||A Label which is displayed in above all errors to notify the user that the warning section starts here|
|scriptingLanguage||Java, Groovy or an empty String||Scripting language filter, here you can set which scripting engines compile errors should be displayed, currently Java or Groovy are supported as values if you leave the attribute empty or set nothing then everything is displayed|
The second cornerstone of Ext-Scripting is change tracking and dependency detection. Now if you have changed a file, Ext-Scripting tracks the changes and also marks most classes which have a dependency to your class as changed.
Again usually the output is pushed into the log as following:
INFO: [EXT-SCRIPTING] Tainting: org/apache/myfaces/javaloader/componentTest/MyComponentTag.java
Again, to get a quick overview within your running page, or preferably an extra page, you can use a specialized component which gives you a quick overview over the change history of the system.
Here our change history component comes into play. With it you can track a certain number of changes done over time including their marked dependencies.
The change history component can be currently used in Facelets only as follows
<exs:taintHistory noEntries="5" />
Following attributes can be used
|Attribute Name||Possible Values||Description|
|noEntries||The <Integer Value> number of entries of the current history||A positive Integer value which shows the last N entries of your history beginning with the latest change marker on top|
Ext-Scripting automatically compiles with the debug flags on. Debugging against a running configuration should be no problem. If the debugger can be pointed towards the sources, debugging should work without any sideeffects.
Due to the fact that the debugger can pick up the debug info from the newly compiled class files. (Note - the class files are not altered in any way so in any case you just deal with normal Java classes)TODO add video here
One of the goals of Ext-Scripting is to prevent unnecessary restarts and redeploys during development. To enable this it provides custom functionality outside of the scope of providing scripting capabilities. One of those features is the page and resource reloading from your source directories.
Pages and web-resources like CSS files or images are loaded from your resource directory without having to redeploy the web application, changes on them can be watched on the fly simple by a browser reload. There is no need to adjust your web application server or your IDE for auto deployment mechanisms. Unnecessary web application restarts for changed resources can be avoided that way. Note while page reloading works on the fly for both JSF 1.2 and JSF 2.x+, resource reloading only works for JSF2.x+, if you need similar functionality for JSF 1.x you can use a third party resource loading library like Weblets.
The central point of setting up your resource reloading are two configuration parameters
The first parameter org.apache.myfaces.extensions.scripting.resource.LOADER_PATHS defines the root path for your resources (aka everything web related, like xhtml facelet templates css files etc..). Note, despite being called resource LOADER_PATH in most cases this path will just be pointed to the your source web application root directory. (ie: src/main/webapp in a standard Maven2 structure or <project-root>/webapp for a standard Eclipse project structure. The name resource just refers to the fact that for Ext-Scripting every web related file is seen as resource
The second parameter facelets.RESOURCE_RESOLVER is responsible for enabling the resouce loading of facelet templates and pages, since Facelets does not have an auto plugging mechanism this has to be set to a standard value which is org.apache.myfaces.extensions.scripting.facelet.ReroutingResourceResolver
For further reference please also visit out Appendix: Configuration Entries Overview page.
Ext-Scripting tries to avoid as many server restarts as possible. To enable this it needs to unload recompile and load artifacts and the those which reference our changed ones. To enable this, Ext-Scripting does dependency detection on bytecode level as well as on artifact level. This functionality is enabled automatically you wont have anything further to do. You can see it working by watching the output log, if you change a class, you automatically will see that the system marks the classes which reference your changed class as tainted as well.
You have to have in mind that data currently in ram cannot be recovered by the unloading and reloading happening, so everything stored for instance in application or session scope is lost that way.
Following video shows the mechanism working:
This dependency detection works over all dynamic classes, no matter being it classes, interfaces, annotations, and it works over static and dynamic imports.
Javabean dependencies also are detected on artifact level so that if the JSF IOC mechanism is used those bound over neutral Object classes also will reload the dependencies correctly.
One of the main features which Ext-Scripting provides over standard JSF is dynamic annotations. Dynamic annotations basically introduces a mechanism so that your standard JSF annotations like @ManagedBean or @FacesComponent or @ManagedProperty or even the scopes like @RequestScoped or @SessionScoped can be changed on the fly in a dynamic way.
To enable this mechanism you don't have to do anything, it comes out of the box in a MyFaces 2.0 environment. Following video demonstrates the mechanism
Ext-Scripting supports following JSF 1.2 artifact reloading:
- ApplicationFactory reloading on method call level
- FacesContextFactory reloading on method call level
- LifecycleFactory reloading on method call level
- RenderkitFactory reloading on method call level
- Converter (on JSF level alone)
- Validator (on JSF level alone)
- Component reloading on component tree creation level (on JSF level alone)
- ManagedBeans reloading for all managed beans even session and application scoped ones on request level
- Support for either JavaC or JSR 199 depending on your JDK Version
- Support for Groovy and Java
Ext-Scripting supports following JSF 2.0 artifact reloading: Additionally to what is present for JSF 1.2
- Component limitations have been lifted for Facelets as rendering language
- All major JSF 2 annotations can be used in a dynamic way, annotations can be moved removed or added on the fly
- Support for Reloading on ComponentTagHandler, ConverterTagHandler, BehaviorTagHandler, ValidatorTagHandler
- ComponentSystemEvent Support via dynamic Annotations
- Application System Event Support
While the target of supporting extension frameworks will be post 1.0 Ext-Scripting already supports dynamic bean validation and Ext-Val
To setup Ext-Val simply add the needed dependencies and you can start to use it instantly
The MyFaces 2.0 demo has a simple example ported over from the Ext-Val distribution which shows the dynamic aspects of using Ext-Val and Ext-Scripting combined
The same what applies to Ext-Val also applies to straight bean validation.
Note at the time of release, the current stable version of Ext-Val has a bug which enforces one manual configuration entry!
<application> <!-- disable an Ext-Val warning which is triggered falsely by the latest version --> <system-event-listener> <system-event-listener-class>org.apache.myfaces.extensions.scripting.startup.SuppressExtValWarningStartupListener</system-event-listener-class> <system-event-class>javax.faces.event.PostConstructApplicationEvent</system-event-class> </system-event-listener> </application>
Currently there is no direct Spring support for Ext-Scripting, it however is in the works and will be delivered in a release post 1.0
While Ext-Scripting itself is only used for rapid prototyping following two szenarii will probably occur in a typical user development environment
while it makes sense to have the Groovy sources for editing, for the final deployment, it makes sense to just deliver the classes instead of the source files. While doing that for your ide is out of scope of this documentation (currently). The documentation can provide you the information on how to do it in Apache Maven:
The trick is to combine two things. Apache Maven 2 profiles and the Apache Maven2 groovy plugin
For a short explanation on Apache Maven 2 profiles please follow this link: Apache Maven 2 Profiles
The idea is, to define a deployment profile which triggers the Maven 2 groovy plugin which then will compile your classes, here is an example configuration of such a profile, which can be copy pasted into your build file
<profiles> <profile> <id>deployment</id> <plugins> <plugin> <groupId>org.codehaus.gmaven</groupId> <artifactId>gmaven-plugin</artifactId> <version>1.2</version> <configuration> <providerSelection>1.7</providerSelection> </configuration> <executions> <execution> <goals> <goal>generateStubs</goal> <goal>compile</goal> <goal>generateTestStubs</goal> <goal>testCompile</goal> </goals> </execution> </executions> <dependencies> <dependency> <groupId>org.codehaus.groovy</groupId> <artifactId>groovy-all</artifactId> <version>1.7.1</version> </dependency> </dependencies> </plugin> </profile> </plugins> </profiles>
The standard settings of the groovy maven plugin is that it will use your src/main/groovy directory as the path to pickup the sources. You either can use that one and adjust the corresponding org.apache.myfaces.extensions.scripting.groovy.LOADER_PATHS setting for editing. Or you can readjust the corresponding plugin settings of the Groovy Maven plugin. Follow this link for further information.
A call to maven clean install -P deployment now triggers the groovy compile task. You also can use the extended features of the maven profiles to automate the switch if you use maven also for deployment of your project.
One problem you might have noticed is, that if you do not work with the default configuration on your sources (aka. WEB-INF/<scripting-language>, you have to rely on the corresponding configuration entries, which in itself take absolute paths. One user of the system came up with the question, on how to deal with multiple developers. The answer is plain and simple, unfortunately the support of such a use case could be better for 1.0, all you can do is either to rely on the default paths, or use your build system to handle the configuration parts per user, or standardize on the same file structure for every user. Additional support for this scenario will be added post 1.0 to ease this usecase but for now it is a known but not entirely solved problem.