[xwiki-devs] [DISCUSSION] Implementing an XWiki component in groovy
Hi All, When working on officeimporter document splitting feature we wanted to make it possible to provide hooks so that the whole import process can be customized external to the officeimporter module via a groovy class (on a wiki page). Since we were in a little hurry, the solution we devised might be called "hackish"; we provided the following interface which can be implemented in groovy: <code> public interface OfficeImporterFilter { void filter(String documentName, Document document); void filter(String documentName, XDOM xdom, boolean isSplit); String filter(String documentName, String content, boolean isSplit); void setDocBridge(DocumentAccessBridge docBridge); } </code> Now, Officeimporter application would pass a parameter into DefaultOfficeImporter indicating the wiki page which contains the groovy filter implementation. Then we do something like: <code> String groovyFilterParam = params.get("groovyFilter"); String groovyScript = docBridge.getDocumentContent(groovyFilterParam); GroovyClassLoader gcl = new GroovyClassLoader(); OfficeImporterFilter importerFilter = (OfficeImporterFilter) gcl.parseClass(groovyScript).newInstance(); importerFilter.setDocBridge(docBridge); return importerFilter; } </code> The purpose of setDocBridge() method is to inject the DAB into the filter so that it can access wiki documents. Now I question myself why it is not possible for a groovy class to access wiki documents without the DAB. This also proves that this solution was not well planned or discussed with the community. Another problem with the filter interface is that it does several things. It would have been better to have three filters instead. Now to the topic of this email; if we can allow groovy code to implement XWiki components (if it is possible), we can make this whole thing very simple. For an example, officeimporter application would pass the role-hint of the component implementing a particular filter (which is a groovy implementation) and DefaultOfficeImporter will simply lookup this component and use it. As for implementing this kind of a mechanism, we can follow something similar to what we did with wiki macros. A special class XWiki.XWikiComponent would contain fields like componentRole (String), roleHint (String) & groovyClass(TextArea) and when a document with an object of XWiki.WikiComponent is saved, we can register a new component against the CM. This idea was suggested to me by vincent & I thought it's time to start a discussion about this to see what others think. Although I have few unclear points (like how dependency injection would work), I think it would be a handy tool to have. Thanks in advance for your comments & suggestions :) - Asiri PS: OfficeImporter code has been polluted a lot because I have stuffed a lot of features into it without properly designing them. I will be refactoring officeimporter a little by little in coming days (as time permits).
On Sat, Aug 8, 2009 at 20:50, Asiri Rathnayake<[email protected]> wrote:
Hi All,
When working on officeimporter document splitting feature we wanted to make it possible to provide hooks so that the whole import process can be customized external to the officeimporter module via a groovy class (on a wiki page). Since we were in a little hurry, the solution we devised might be called "hackish"; we provided the following interface which can be implemented in groovy:
<code> public interface OfficeImporterFilter {
void filter(String documentName, Document document);
void filter(String documentName, XDOM xdom, boolean isSplit);
String filter(String documentName, String content, boolean isSplit);
void setDocBridge(DocumentAccessBridge docBridge);
} </code>
Now, Officeimporter application would pass a parameter into DefaultOfficeImporter indicating the wiki page which contains the groovy filter implementation. Then we do something like:
<code> String groovyFilterParam = params.get("groovyFilter"); String groovyScript = docBridge.getDocumentContent(groovyFilterParam); GroovyClassLoader gcl = new GroovyClassLoader(); OfficeImporterFilter importerFilter = (OfficeImporterFilter) gcl.parseClass(groovyScript).newInstance(); importerFilter.setDocBridge(docBridge); return importerFilter; } </code>
The purpose of setDocBridge() method is to inject the DAB into the filter so that it can access wiki documents. Now I question myself why it is not possible for a groovy class to access wiki documents without the DAB. This also proves that this solution was not well planned or discussed with the community. Another problem with the filter interface is that it does several things. It would have been better to have three filters instead.
Now to the topic of this email; if we can allow groovy code to implement XWiki components (if it is possible), we can make this whole thing very simple. For an example, officeimporter application would pass the role-hint of the component implementing a particular filter (which is a groovy implementation) and DefaultOfficeImporter will simply lookup this component and use it.
As for implementing this kind of a mechanism, we can follow something similar to what we did with wiki macros. A special class XWiki.XWikiComponent would contain fields like componentRole (String), roleHint (String) & groovyClass(TextArea) and when a document with an object of XWiki.WikiComponent is saved, we can register a new component against the CM.
This idea was suggested to me by vincent & I thought it's time to start a discussion about this to see what others think. Although I have few unclear points (like how dependency injection would work), I think it would be a handy tool to have.
Thanks in advance for your comments & suggestions :)
Note that you can register an component you want simply by using the component manager api. So this work with any language as soon as it can access Utils.getComponentManager() and has class and object support (like groovy for example). So the quickest way would be to list pages to execute at startup. Among other things they could register any component they want.
- Asiri
PS: OfficeImporter code has been polluted a lot because I have stuffed a lot of features into it without properly designing them. I will be refactoring officeimporter a little by little in coming days (as time permits). _______________________________________________ devs mailing list [email protected] http://lists.xwiki.org/mailman/listinfo/devs
-- Thomas Mortagne
On Sat, Aug 8, 2009 at 20:50, Asiri Rathnayake<[email protected]> wrote:
Hi All,
When working on officeimporter document splitting feature we wanted to make it possible to provide hooks so that the whole import process can be customized external to the officeimporter module via a groovy class (on a wiki page). Since we were in a little hurry, the solution we devised might be called "hackish"; we provided the following interface which can be implemented in groovy:
<code> public interface OfficeImporterFilter {
void filter(String documentName, Document document);
void filter(String documentName, XDOM xdom, boolean isSplit);
String filter(String documentName, String content, boolean isSplit);
void setDocBridge(DocumentAccessBridge docBridge);
} </code>
Now, Officeimporter application would pass a parameter into DefaultOfficeImporter indicating the wiki page which contains the groovy filter implementation. Then we do something like:
<code> String groovyFilterParam = params.get("groovyFilter"); String groovyScript = docBridge.getDocumentContent(groovyFilterParam); GroovyClassLoader gcl = new GroovyClassLoader(); OfficeImporterFilter importerFilter = (OfficeImporterFilter) gcl.parseClass(groovyScript).newInstance(); importerFilter.setDocBridge(docBridge); return importerFilter; } </code>
The purpose of setDocBridge() method is to inject the DAB into the filter so that it can access wiki documents. Now I question myself why it is not possible for a groovy class to access wiki documents without the DAB. This also proves that this solution was not well planned or discussed with the community. Another problem with the filter interface is that it does several things. It would have been better to have three filters instead.
Now to the topic of this email; if we can allow groovy code to implement XWiki components (if it is possible), we can make this whole thing very simple. For an example, officeimporter application would pass the role-hint of the component implementing a particular filter (which is a groovy implementation) and DefaultOfficeImporter will simply lookup this component and use it.
As for implementing this kind of a mechanism, we can follow something similar to what we did with wiki macros. A special class XWiki.XWikiComponent would contain fields like componentRole (String), roleHint (String) & groovyClass(TextArea) and when a document with an object of XWiki.WikiComponent is saved, we can register a new component against the CM.
This idea was suggested to me by vincent & I thought it's time to start a discussion about this to see what others think. Although I have few unclear points (like how dependency injection would work), I think it would be a handy tool to have.
Thanks in advance for your comments & suggestions :)
Now for the things which work even with velocity it's more complex for doing it the generic way. One solution I can think of right now: - first have class/objects to mimic component descriptor (like we do for wiki macros) - a jmock like dynamic proxy which will be registered to the component Manager (because you have to implement the proper interface to give it to the CM) - when a method is called we execute the page content with in the context a "component" object (like the "macro" object of wiki macros) - $context.component.fieds.set/getField1 to store anything a component want to persist in the component instance (if it's not a per-lookup component) - $context.component.method return the name of the method called we can then organise the script with some #if/#elseif based on the method name (or call the corresponding method of the object it stored in component.fields the first time it has been called, for language like groovy which i'm sure have easy tools to call an object method from a string) - $component.parameters.param1 to get the parameters of the method - $component.setResult() to inject to the result of the execution
- Asiri
PS: OfficeImporter code has been polluted a lot because I have stuffed a lot of features into it without properly designing them. I will be refactoring officeimporter a little by little in coming days (as time permits). _______________________________________________ devs mailing list [email protected] http://lists.xwiki.org/mailman/listinfo/devs
-- Thomas Mortagne
participants (2)
-
Asiri Rathnayake -
Thomas Mortagne