Changes for page Creating XWiki Components

Last modified by Simon Urli on 2023/10/10

<
From version < 25.4 >
edited by yang ningJian
on 2010/02/12
To version < 26.1 >
edited by Silvia Macovei
on 2010/02/25
>
Change comment: Document converted from syntax xwiki/1.0 to syntax xwiki/2.0

Summary

Details

Page properties
Author
... ... @@ -1,1 +1,1 @@
1 -XWiki.YangNingYuan
1 +XWiki.SilviaRusu
Syntax
... ... @@ -1,1 +1,1 @@
1 -XWiki 1.0
1 +XWiki 2.0
Content
... ... @@ -1,66 +1,74 @@
1 -1 Writing XWiki components
1 += Writing XWiki components =
2 2  
3 -#toc("", "", "")
3 +{{toc start="" depth="" numbered=""/}}
4 4  
5 5  This tutorial guides you through the creation of an XWiki component, which replaces the Plugin architecture and which is now the recommended way of writing XWiki modules. They should be able to execute any Java code and communicate with XWiki by using the existing XWiki (core) components, as well as being exposed to the XWiki documents scripting environment (velocity and groovy).
6 6  
7 -You should start by reading the [Reference document on XWiki Components>code:Modules.ComponentModule].
7 +You should start by reading the [[Reference document on XWiki Components>>code:Modules.ComponentModule]].
8 8  
9 -#warning("The tutorial below is slightly outdated since some changes have been brought to the Component Module since it was written. See the [Reference document on XWiki Components>code:Modules.ComponentModule] for fresh information. This tutorial needs to be rewritten and duplicate with the Reference document removed.")
9 +{{warning}}The tutorial below is slightly outdated since some changes have been brought to the Component Module since it was written. See the [[Reference document on XWiki Components>>code:Modules.ComponentModule]] for fresh information. This tutorial needs to be rewritten and duplicate with the Reference document removed.{{/warning}}
10 10  
11 -1.1 Let's get started!
11 +== Let's get started! ==
12 12  
13 13  Enough talking, let's see some code!
14 14  
15 15  In the followings we will guide you through writing a simple component, helping you to quickly get oriented in XWiki components world and explaining how it works.
16 16  
17 -1.1.1 Creating a XWiki component using maven
17 +=== Creating a XWiki component using maven ===
18 18  
19 -To simplify the three steps process of component creation in XWiki, and since the XWiki code lifecycle is based on [maven>http://maven.apache.org/], we have created a maven archetype to help create a simple component module with a single command, with respect to the XWiki architecture and components specific requirements.
20 -* download the archetype from here: {attach:xwiki-archetype-component-1.0-SNAPSHOT.jar} (it will soon be uploaded on our maven repository).
21 -* use maven to install this file on your local repository by executing (make sure you replace <tt>path-to-jar-file</tt> with your own path):
22 -{code}
23 -mvn install:install-file -Dfile=<path-to-jar-file> -DartifactId=xwiki-archetype-component -DgroupId=com.xpn.xwiki.platform.tools -Dversion=1.0-SNAPSHOT -Dpackaging=jar
24 -{code}
19 +To simplify the three steps process of component creation in XWiki, and since the XWiki code lifecycle is based on [[maven>>http://maven.apache.org/]], we have created a maven archetype to help create a simple component module with a single command, with respect to the XWiki architecture and components specific requirements.
20 +
21 +* download the archetype from here: attach:xwiki-archetype-component-1.0-SNAPSHOT.jar (it will soon be uploaded on our maven repository).
22 +* use maven to install this file on your local repository by executing (make sure you replace ##path-to-jar-file## with your own path):
23 +
24 +{{code}}mvn install:install-file -Dfile=<path-to-jar-file> -DartifactId=xwiki-archetype-component -DgroupId=com.xpn.xwiki.platform.tools -Dversion=1.0-SNAPSHOT -Dpackaging=jar{{/code}}
25 +
25 25  * now you're ready to use maven to generate the xwiki component based on this archetype. Navigate to the directory where you want your component to be located and type:
26 -{code}
27 -mvn archetype:generate -DarchetypeGroupId=com.xpn.xwiki.platform.tools -DarchetypeArtifactId=xwiki-archetype-component -DarchetypeVersion=1.0-SNAPSHOT -DgroupId=<component-group-id> -DartifactId=<component-artifact-id> -Dpackage=<component-package> -Dversion=<component-version> -Dpackaging=jar
28 -{code}
29 -where you replace <tt>component-group-id</tt>, <tt>component-artifact-id</tt>, <tt>component-package</tt>, <tt>component-version</tt> with the corresponding values for your component. To create a server XWiki Watch component, for example, we used <tt>-DgroupId=com.xpn.xwiki.products -DartifactId=xwiki-watch-component -Dpackage=org.xwiki.watch.component -Dversion=1.1-SNAPSHOT</tt>. Don't forget to follow the [xwiki package names guidelines > http://dev.xwiki.org/xwiki/bin/view/Community/CodeStyle#HPackagenames-1].
30 30  
31 -Now this will create a new maven module in a folder named <tt>component-artifact-id</tt> in your folder, with a default xwiki component inside.
32 -#info("Note that if your parent (current, from where you are executing maven) folder is the folder of a maven module (contains a <tt>pom.xml</tt> file), then the command above will fail unless the module is packaged as <tt>pom</tt>. If the project is packaged as <tt>pom</tt>, then the newly created module will be added in its modules list, and the parent of the newly created component module will be set to this project's <tt>pom</tt>.")
28 +{{code}}mvn archetype:generate -DarchetypeGroupId=com.xpn.xwiki.platform.tools -DarchetypeArtifactId=xwiki-archetype-component -DarchetypeVersion=1.0-SNAPSHOT -DgroupId=<component-group-id> -DartifactId=<component-artifact-id> -Dpackage=<component-package> -Dversion=<component-version> -Dpackaging=jar{{/code}}
33 33  
34 -1.1.1 The component explained
30 +where you replace ##component-group-id##, ##component-artifact-id##, ##component-package##, ##component-version## with the corresponding values for your component. To create a server XWiki Watch component, for example, we used ##-DgroupId=com.xpn.xwiki.products -DartifactId=xwiki-watch-component -Dpackage=org.xwiki.watch.component -Dversion=1.1-SNAPSHOT##. Don't forget to follow the [[xwiki package names guidelines>>http://dev.xwiki.org/xwiki/bin/view/Community/CodeStyle#HPackagenames-1]].
35 35  
36 -Assume, for the following explanations, that the package you used is <tt>org.xwiki.component</tt>
32 +Now this will create a new maven module in a folder named ##component-artifact-id## in your folder, with a default xwiki component inside. {{info}}Note that if your parent (current, from where you are executing maven) folder is the folder of a maven module (contains a ##pom.xml## file), then the command above will fail unless the module is packaged as ##pom##. If the project is packaged as ##pom##, then the newly created module will be added in its modules list, and the parent of the newly created component module will be set to this project's ##pom##.{{/info}}
37 37  
34 +=== The component explained ===
35 +
36 +Assume, for the following explanations, that the package you used is ##org.xwiki.component##
37 +
38 38  Navigating in the component project folder, you will see standard maven project structure like this:
39 -{code}
39 +
40 +{{code}}
40 40  pom.xml
41 41  src/main/java/org/xwiki/component/HelloWorld.java
42 42  src/main/java/org/xwiki/component/internal/DefaultHelloWorld.java
43 43  src/main/resources/META-INF/components.txt
44 44  src/test/java/org/xwiki/component/HelloWorldTest.java
45 -{code}
46 -which corresponds to the default files created: the <tt>HelloWorld</tt> interface (service), its implementation <tt>DefaultHelloWorld</tt>, a test class for this component <tt>HelloWorldTest</tt>, the component declaration file <tt>components.txt</tt> and the maven project <tt>pom</tt> file.
46 +{{/code}}
47 47  
48 -If we have a look in the <tt>pom</tt>, we see something like this:
49 -{code}
50 - <groupId>your-group-id</groupId>
48 +which corresponds to the default files created: the ##HelloWorld## interface (service), its implementation ##DefaultHelloWorld##, a test class for this component ##HelloWorldTest##, the component declaration file ##components.txt## and the maven project ##pom## file.
49 +
50 +If we have a look in the ##pom##, we see something like this:
51 +
52 +{{code}}
53 +<groupId>your-group-id</groupId>
51 51   <artifactId>your-artifact-id</artifactId>
52 52   <version>your-version</version>
53 -{code}
56 +{{/code}}
57 +
54 54  which are the group, artifact and version you used when you created your component
55 -{code}
56 - <properties>
59 +
60 +{{velocity filter="none"}}
61 +{{html clean="false" wiki="true"}}
62 +{{code}}
63 +<properties>
57 57   <!-- TODO: remove this if you inherit a project that has the core version set -->
58 58   <platform.core.version>1.8-SNAPSHOT</platform.core.version>
59 59   </properties>
60 -{code}
61 -It defines the core version for the <tt>xwiki-component-api</tt> dependency. If your component is created as part of a project already depending on the core (and which most probably already has a property for the core version), use the inherited property value instead of redefining it here. Or, if the component should have the same version as the rest of the XWiki modules, you can use <tt>${pom.version}</tt> as the version for other XWiki dependencies.
62 -{code}
63 - <dependencies>
67 +{{/code}}
68 +It defines the core version for the ##xwiki-component-api## dependency. If your component is created as part of a project already depending on the core (and which most probably already has a property for the core version), use the inherited property value instead of redefining it here. Or, if the component should have the same version as the rest of the XWiki modules, you can use ##${pom.version}## as the version for other XWiki dependencies.
69 +
70 +{{code}}
71 +<dependencies>
64 64   <dependency>
65 65   <groupId>org.xwiki.platform</groupId>
66 66   <artifactId>xwiki-core-component-api</artifactId>
... ... @@ -74,50 +74,54 @@
74 74   </dependency>
75 75   <!-- Add here all your other dependencies -->
76 76   </dependencies>
77 -{code}
78 -The code above defines the dependency on the <tt>xwiki-component module-api</tt> in the core and the junit for the testing phase and, of course, marks the spot for you to add all your other components, modules, and library dependencies for maven to know and put them on your classpath when compiling, etc.
79 -
85 +{{/code}}
86 +The code above defines the dependency on the ##xwiki-component module-api## in the core and the junit for the testing phase and, of course, marks the spot for you to add all your other components, modules, and library dependencies for maven to know and put them on your classpath when compiling, etc.
87 +<p/>
80 80  To inherit all the properties of the platform projects (among others, source and target compatibility with <b>Java 1.5</b>), we inherit our project from the platform pom:
81 -{code}
82 - <parent>
89 +
90 +{{code}}
91 +<parent>
83 83   <groupId>org.xwiki.platform</groupId>
84 84   <artifactId>xwiki</artifactId>
85 85   <version>28</version>
86 86   </parent>
87 -{code}
96 +{{/code}}
88 88  
89 -The interface file (<tt>HelloWorld.java</tt>) contains the definition of a regular Java interface, and looks like this:
90 -{code}
98 +The interface file (##HelloWorld.java##) contains the definition of a regular Java interface, and looks like this:
99 +
100 +{{code}}
91 91  @ComponentRole /* annotation used for declaring the service our component will provide */
92 92  public interface HelloWorld
93 93  {
94 94   String sayHello();
95 95  }
96 -{code}
106 +{{/code}}
97 97  
108 +Keep in mind that only this interface specifies the functions the other components will use to communicate with our component, no other functions besides the ones defined in this interface will be accessible to the "outside world". In our case, we'll build a polite component that can only ##sayHello()##.
109 +<p/>
110 +Then we have the implementation of the interface, the ##DefaltHelloWorld## class.
98 98  
99 -Keep in mind that only this interface specifies the functions the other components will use to communicate with our component, no other functions besides the ones defined in this interface will be accessible to the "outside world". In our case, we'll build a polite component that can only <tt>sayHello()</tt>.
100 -
101 -Then we have the implementation of the interface, the <tt>DefaltHelloWorld</tt> class.
102 -{code}
112 +{{code}}
103 103  @Component
104 104  public class DefaultHelloWorld extends AbstractLogEnabled implements HelloWorld, Initializable
105 -{code}
115 +{{/code}}
106 106  
107 -Notice the <tt>@Component</tt> annotation used for declaring the implementation for the component. Optionally, a component implementation can have a ~~hint~~ assigned. This is useful especially when we want to distinguish between several implementations for the same type of component. In this case, the <tt>DefaltHelloWorld</tt> class would look like this:
108 -{code}
117 +Notice the ##@Component## annotation used for declaring the implementation for the component. Optionally, a component implementation can have a //hint// assigned. This is useful especially when we want to distinguish between several implementations for the same type of component. In this case, the ##DefaltHelloWorld## class would look like this:
118 +
119 +{{code}}
109 109  @Component("myCustomHelloWorld")
110 110  public class DefaultHelloWorld extends AbstractLogEnabled implements HelloWorld, Initializable
111 -{code}
122 +{{/code}}
112 112  We can go even deeper into more advanced issues and specify multiple component hints for the same implementation, if we want. This can be done as follows:
113 -{code}
124 +
125 +{{code}}
114 114  @Component(hints = {"info", "warning", "error" })
115 115  public class DefaultHelloWorld extends AbstractLogEnabled implements HelloWorld, Initializable
116 -{code}
128 +{{/code}}
117 117  
118 -This class extends <tt>AbstractLogEnabled</tt> to be able to use the logging system, implements the component interface, and also the <tt>Initializable</tt> interface which allows it to hook initialization code upon its instantiation by the component manager, in the <tt>initialize()</tt> function:
130 +This class extends ##AbstractLogEnabled## to be able to use the logging system, implements the component interface, and also the ##Initializable## interface which allows it to hook initialization code upon its instantiation by the component manager, in the ##initialize()## function:
119 119  
120 -{code}
132 +{{code}}
121 121  public void initialize() throws InitializationException
122 122  {
123 123   // TODO: initialize component
... ... @@ -124,10 +124,9 @@
124 124   // getLogger is inherited from AbstractLogEnabled
125 125   getLogger().debug("DefaultHelloWorld initialized");
126 126  }
127 -{code}
139 +{{/code}}
128 128  
129 -{code}
130 -
141 +{{code}}
131 131  /**
132 132   * Says hello by returning a greeting to the caller.
133 133   *
... ... @@ -137,26 +137,24 @@
137 137  {
138 138   return "Hello world!";
139 139  }
140 -{code}
151 +{{/code}}
141 141  
142 -And now, the <tt>components.txt</tt> file, in which component implementations present in this jar are specified for the <tt>ComponentManager</tt> to register them
143 -{code}
144 -org.xwiki.component.internal.DefaultHelloWorld
145 -{code}
153 +And now, the ##components.txt## file, in which component implementations present in this jar are specified for the ##ComponentManager## to register them
146 146  
155 +{{code}}org.xwiki.component.internal.DefaultHelloWorld{{/code}}
147 147  
157 +== How to find my component and use it? ==
148 148  
149 -1.1 How to find my component and use it?
159 +=== From other components ===
150 150  
151 -1.1.1 From other components
152 -
153 153  To access your component from another component we use the components engine, and specify the dependencies declarative, leaving instantiation and component injection to the be handled by the component manager. The most straightforward way is the use of the requirements mechanism of plexus, specifying that our component is required by the component that needs to access it.
154 -
162 +<p/>
155 155  Don't forget that any code that uses the component we wrote needs to have the component interface accessible in its classpath. Even if instantiation and dependency is handled by the engine at runtime, the code still needs to compile.
156 156  If the two components are not in the same module (the same .jar), don't forget to add the module of the greeter component as a dependency of the module of any component that uses it.
165 +<p/>
166 +Then, to effectively use the ##HelloWorld## component, we need a reference to it in the the component that uses it. For this, we use a member variable in the implementation of the using component, for example, a ##Socializer## component will need to be able to say hello to the world:
157 157  
158 -Then, to effectively use the <tt>HelloWorld</tt> component, we need a reference to it in the the component that uses it. For this, we use a member variable in the implementation of the using component, for example, a <tt>Socializer</tt> component will need to be able to say hello to the world:
159 -{code}
168 +{{code}}
160 160  @Component
161 161  public class DefaultSocializer extends AbstractLogEnabled implements Socializer, Initializable
162 162  {
... ... @@ -168,18 +168,17 @@
168 168  
169 169   [...]
170 170  }
171 -{code}
180 +{{/code}}
172 172  
173 -Note the <tt>@Requirement</tt> annotation, which instructs the component manager to inject the required component where needed.
182 +Note the ##@Requirement## annotation, which instructs the component manager to inject the required component where needed.
183 +<p/>
184 +The content of ##components.txt## should be updated with:
174 174  
175 -The content of <tt>components.txt</tt> should be updated with:
176 -{code}
177 -org.xwiki.component.internal.DefaultSocializer
178 -{code}
186 +{{code}}org.xwiki.component.internal.DefaultSocializer{{/code}}
179 179  
180 -And that's it, you can now use the <tt>helloWorld</tt> member anywhere in the <tt>DefaultSocializer</tt> class freely, without further concerns, it will be assigned by the component manager provided that the <tt>HelloWorld</tt> component is on the classpath at runtime when the <tt>Socializer</tt> is used. Such as:
188 +And that's it, you can now use the ##helloWorld## member anywhere in the ##DefaultSocializer## class freely, without further concerns, it will be assigned by the component manager provided that the ##HelloWorld## component is on the classpath at runtime when the ##Socializer## is used. Such as:
181 181  
182 -{code}
190 +{{code}}
183 183  public class DefaultSocializer extends AbstractLogEnabled implements Socializer, Initializable
184 184  {
185 185   [...]
... ... @@ -193,51 +193,52 @@
193 193  
194 194   [...]
195 195  }
196 -{code}
204 +{{/code}}
197 197  
198 -More, note that all through the process of defining a communication path between two components, we never referred components implementations, all specifications being done through ~~roles~~ and ~~interfaces~~: the implementation of a service is completely hidden from any code external to the component.
199 -
206 +More, note that all through the process of defining a communication path between two components, we never referred components implementations, all specifications being done through //roles// and //interfaces//: the implementation of a service is completely hidden from any code external to the component.
207 +<p/>
200 200  TODO: refer to the other ways of implementing dependencies but requirements mechanism. Details, explanations, links.
201 201  
202 -1.1.1 From non-components java code (e.g. older plugins)
210 +=== From non-components java code (e.g. older plugins) ===
203 203  
204 -For this kind of usages, since we cannot use the component-based architecture advantages and the "magic" of the component manager, the XWiki team has created a helper method that acts like a bridge between component code and non-component code, the <tt>com.xpn.xwiki.web.Utils.getComponent(String role, String hint)</tt> that gets the specified component instance from the component manager and returns it. As seen in the previous sections, the hint is an optional identifier, additional to <tt>role</tt>, used to differentiate between implementations of the same interface: the ~~roles~~ identify services while the hints help differentiate between implementations (see more at [http://plexus.codehaus.org/guides/developer-guide/building-components/component-identity.html > http://plexus.codehaus.org/guides/developer-guide/building-components/component-identity.html]). The <tt>getComponent</tt> function also has a version without the <tt>hint</tt> parameter, that uses the default hint.
205 -
212 +For this kind of usages, since we cannot use the component-based architecture advantages and the "magic" of the component manager, the XWiki team has created a helper method that acts like a bridge between component code and non-component code, the ##com.xpn.xwiki.web.Utils.getComponent(String role, String hint)## that gets the specified component instance from the component manager and returns it. As seen in the previous sections, the hint is an optional identifier, additional to ##role##, used to differentiate between implementations of the same interface: the //roles// identify services while the hints help differentiate between implementations (see more at [[http://plexus.codehaus.org/guides/developer-guide/building-components/component-identity.html>>http://plexus.codehaus.org/guides/developer-guide/building-components/component-identity.html]]). The ##getComponent## function also has a version without the ##hint## parameter, that uses the default hint.
213 +<p/>
206 206  To use our greetings provider component, we simply invoke:
207 -{code}
215 +
216 +{{code}}
208 208  HelloWorld greeter = (HelloWorld) Utils.getComponent(HelloWorld.class);
209 209  //use the HelloWorld service
210 210  greeter.sayHello();
211 -{code}
220 +{{/code}}
212 212  
213 -Note that, even if, in fact, the object returned by this function is an instance of the DefaultHelloWorld, you should *never declare your object of the implementation type nor cast to implementation instead of interface*. A component is represented by its interface, the implementation for such a service can be provided by any code, any class so relying on the implementation type is neither good practice (since the interface contract should be enough for a component), nor safe. In the future, a maven enforcer plugin will be setup in the build lifecycle, so that any reference to component implementations (located in an "internal" subpackage) will cause build errors.
222 +Note that, even if, in fact, the object returned by this function is an instance of the DefaultHelloWorld, you should **never declare your object of the implementation type nor cast to implementation instead of interface**. A component is represented by its interface, the implementation for such a service can be provided by any code, any class so relying on the implementation type is neither good practice (since the interface contract should be enough for a component), nor safe. In the future, a maven enforcer plugin will be setup in the build lifecycle, so that any reference to component implementations (located in an "internal" subpackage) will cause build errors.
223 +<p/>
224 +{{info}}The usage of ##Utils.getComponent()## functions is highly discouraged, reserved for this type of situations, when you need to access a component from non-componentized code. For the componentized code, you should use either dependency declaration at 'compile-time' (as shown before with annotations) or, if you need to resolve components dependencies at runtime, use the ComponentManager, which you can access by implementing the Composable interface described above.{{/info}}
214 214  
215 -#info("The usage of <tt>Utils.getComponent()</tt> functions is highly discouraged, reserved for this type of situations, when you need to access a component from non-componentized code. For the componentized code, you should use either dependency declaration at 'compile-time' (as shown before with annotations) or, if you need to resolve components dependencies at runtime, use the ComponentManager, which you can access by implementing the Composable interface described above.")
226 +=== From wiki pages ===
216 216  
217 -1.1.1 From wiki pages
218 -
219 219  In order to use a component in wiki pages, we need to expose it to the scripting environments: groovy and velocity.
220 220  
221 -1.1.1.1 Accessing a component from groovy
230 +==== Accessing a component from groovy ====
222 222  
223 -Since, in groovy, we have access to all classes and functions in XWiki (all this protected by the requirement for programming rights), it means that we can use the same method as in [the previous section > WritingComponents#HFromnoncomponentsjavacode28egolderplugins29], using the <tt>Utils</tt> class. A simple page that would print the greeting from the <tt>HelloWorld</tt> component would look like this (of course, with your own package for the HelloWorld interface):
232 +Since, in groovy, we have access to all classes and functions in XWiki (all this protected by the requirement for programming rights), it means that we can use the same method as in [[the previous section>>WritingComponents#HFromnoncomponentsjavacode28egolderplugins29]], using the ##Utils## class. A simple page that would print the greeting from the ##HelloWorld## component would look like this (of course, with your own package for the HelloWorld interface):
224 224  
225 -{code}
234 +{{code}}
226 226  <%
227 227  def greeter = com.xpn.xwiki.web.Utils.getComponent(org.xwiki.component.HelloWorld.class);
228 228  println greeter.sayHello();
229 229  %>
230 -{code}
239 +{{/code}}
231 231  
232 232  TODO: talk about the future plans (?) to make a component accessible in the groovy context through a groovy bridge.
233 233  
234 -1.1.1.1 Accessing a component from velocity
243 +==== Accessing a component from velocity ====
235 235  
236 236  XWiki dev team is currently working on the design of a VelocityBridge interface that will handle components access from velocity. Until this specification is ready and its first implementation done, we can do it as follows:
246 +<p/>
247 +We write another component in our package, that implements the <a href="http:~//svn.xwiki.org/svnroot/xwiki/platform/core/trunk/xwiki-velocity/src/main/java/org/xwiki/velocity/VelocityContextInitializer.java"><tt>VelocityContextInitializer</tt></a>, which is responsible for the initialization of the velocity context in XWiki through its method ##initialize(VelocityContext context)##, called automatically when a new velocity context is created. As you probably guessed, we will use this function to add our ##HelloWorld## component to the velocity context.
237 237  
238 -We write another component in our package, that implements the <a href="http://svn.xwiki.org/svnroot/xwiki/platform/core/trunk/xwiki-velocity/src/main/java/org/xwiki/velocity/VelocityContextInitializer.java"><tt>VelocityContextInitializer</tt></a>, which is responsible for the initialization of the velocity context in XWiki through its method <tt>initialize(VelocityContext context)</tt>, called automatically when a new velocity context is created. As you probably guessed, we will use this function to add our <tt>HelloWorld</tt> component to the velocity context.
239 -
240 -{code}
249 +{{code}}
241 241  @Component("helloWorld")
242 242  public class HelloWorldVelocityContextInitializer implements VelocityContextInitializer
243 243  {
... ... @@ -256,56 +256,50 @@
256 256   context.put(VELOCITY_CONTEXT_KEY, this.helloWorld);
257 257   }
258 258  }
259 -{code}
268 +{{/code}}
260 260  
261 -The result of this will be the availability of the <tt>HelloWorld</tt> instance in velocity through the key ~~greeter~~ (as in <tt>$greeter.sayHello()</tt>).
270 +The result of this will be the availability of the ##HelloWorld## instance in velocity through the key //greeter// (as in ##$greeter.sayHello()##).
271 +<p/>
272 +This instance of ##HelloWorld## will be injected by the component manager in the ##helloWorld## member, due to the ##@Requirement## annotation.
273 +<p/>
274 +In order to have the ##VelocityContextInitializer## component accessible to the component manager, therefore initialized indeed when a velocity context is created, we specify it as a component in the ##components.txt## file (in our case, the same file where we have ##DefaultHelloWorld## component):
262 262  
263 -This instance of <tt>HelloWorld</tt> will be injected by the component manager in the <tt>helloWorld</tt> member, due to the <tt>@Requirement</tt> annotation.
264 -
265 -In order to have the <tt>VelocityContextInitializer</tt> component accessible to the component manager, therefore initialized indeed when a velocity context is created, we specify it as a component in the <tt>components.txt</tt> file (in our case, the same file where we have <tt>DefaultHelloWorld</tt> component):
266 -{code}
276 +{{code}}
267 267  [...]
268 268  org.component.internal.vcinitializer.HelloWorldVelocityContextInitializer
269 -{code}
279 +{{/code}}
270 270  
271 -Note that this time, we specify a hint for component identification, because we need to differentiate this implementation of the <tt>VelocityContextInitializer</tt> from the other implementations, as it is not the only component with this role in XWiki.
281 +Note that this time, we specify a hint for component identification, because we need to differentiate this implementation of the ##VelocityContextInitializer## from the other implementations, as it is not the only component with this role in XWiki.
282 +<p/>
283 +Of course, in order to for all this to compile, we need to have the ##VelocityContextInitializer## interface available on the classpath so we have this new dependency in the component module's pom:
272 272  
273 -Of course, in order to for all this to compile, we need to have the <tt>VelocityContextInitializer</tt> interface available on the classpath so we have this new dependency in the component module's pom:
274 -{code}
275 - <dependency>
285 +{{code}}
286 +<dependency>
276 276   <groupId>org.xwiki.platform</groupId>
277 277   <artifactId>xwiki-core-velocity</artifactId>
278 278   <version>${platform.core.version}</version>
279 279   </dependency>
280 -{code}
291 +{{/code}}
281 281  
282 -And that's it, you have made your <tt>HelloWorld</tt> component velocity-accessible! Just recompile your package, copy it in the WEB-INF/lib folder of your xwiki webbapp container, and restart the server. You'll be able to get a greeting in velocity through:
283 -{code}
284 -$greeter.sayHello()
285 -{code}
293 +And that's it, you have made your ##HelloWorld## component velocity-accessible! Just recompile your package, copy it in the WEB-INF/lib folder of your xwiki webbapp container, and restart the server. You'll be able to get a greeting in velocity through:
286 286  
287 -For the automatic creation of a velocity accessible xwiki component through this method, we have also created a maven archetype for this purpose too, the {attach:xwiki-archetype-velocity-component-1.0-SNAPSHOT.jar}. Download it and use it as described in [the first part of this tutorial > WritingComponents#HCreatingaXWikicomponentusingmaven].
295 +{{code}}$greeter.sayHello(){{/code}}
288 288  
297 +For the automatic creation of a velocity accessible xwiki component through this method, we have also created a maven archetype for this purpose too, the attach:xwiki-archetype-velocity-component-1.0-SNAPSHOT.jar. Download it and use it as described in [[the first part of this tutorial>>WritingComponents#HCreatingaXWikicomponentusingmaven]].
289 289  
299 +== How do I find other code? ==
290 290  
301 +=== The XWiki data model ===
291 291  
292 -
293 -
294 -
295 -
296 -
297 -1.1 How do I find other code?
298 -
299 -1.1.1 The XWiki data model
300 -
301 -Since the XWiki data model (documents, objects, attachments, etc.) reside in the big, old <tt>xwiki-core</tt> module, and since we don't want to add the whole core and all its dependencies as a dependency of a simple lightweight component (this would eventually lead to a circular dependency, which is not allowed by maven), the current strategy, until the data model is completely turned into a component, is to use a ~~bridge~~ between the new component architecture and the old <tt>xwiki-core</tt>.
302 -
303 -In short, the way this works is based on the fact that implementations for a component don't have to be in the same <tt>.jar</tt> as the interface, and there is no dependency ~~from~~ the component interface ~~to~~ the actual implementation, only the other way around. So, we made a few simple components that offer basic access to XWiki documents, and declared the classes in <tt>xwiki-core</tt> as the default implementation for those components.
304 -
305 -If your component needs to access the XWiki data model, it will use the components from the <tt>xwiki-core-bridge</tt> module for that. Note that these interfaces are rather small, so you can't do everything that you could with the old model. If you need to add some methods to the bridge, feel free to propose it on the [mailing list>dev:Community.MailingLists].
306 -
303 +Since the XWiki data model (documents, objects, attachments, etc.) reside in the big, old ##xwiki-core## module, and since we don't want to add the whole core and all its dependencies as a dependency of a simple lightweight component (this would eventually lead to a circular dependency, which is not allowed by maven), the current strategy, until the data model is completely turned into a component, is to use a //bridge// between the new component architecture and the old ##xwiki-core##.
304 +<p/>
305 +In short, the way this works is based on the fact that implementations for a component don't have to be in the same ##.jar## as the interface, and there is no dependency //from// the component interface //to// the actual implementation, only the other way around. So, we made a few simple components that offer basic access to XWiki documents, and declared the classes in ##xwiki-core## as the default implementation for those components.
306 +<p/>
307 +If your component needs to access the XWiki data model, it will use the components from the ##xwiki-core-bridge## module for that. Note that these interfaces are rather small, so you can't do everything that you could with the old model. If you need to add some methods to the bridge, feel free to propose it on the [[mailing list>>dev:Community.MailingLists]].
308 +<p/>
307 307  For example:
308 -{code}
310 +
311 +{{code}}
309 309  @Component
310 310  public class DefaultHelloWorld implements HelloWorld
311 311  {
... ... @@ -319,17 +319,18 @@
319 319   {
320 320   return documentAccessBridge.getProperty("XWiki.XWikiPreferences", "greeting_text");
321 321   }
322 -{code}
325 +{{/code}}
323 323  
324 -1.1.1 The XWiki context
327 +=== The XWiki context ===
325 325  
326 -Note that the XWiki context is deprecated. It was an older way of keeping track of the current request, which had to be passed around from method to method, looking like a [ball and chain>http://en.wikipedia.org/wiki/Ball_and_chain] present everywhere in the code.
329 +Note that the XWiki context is deprecated. It was an older way of keeping track of the current request, which had to be passed around from method to method, looking like a [[ball and chain>>http://en.wikipedia.org/wiki/Ball_and_chain]] present everywhere in the code.
330 +<p/>
331 +In the component world, the current request information is held in an **[[execution context>>http://maven.xwiki.org/site/xwiki-core-parent/xwiki-core-context/apidocs/org/xwiki/context/ExecutionContext.html]]**. This is actually more powerful than the old XWiki context, as it is a generic execution context, and you can create one anytime you want and use it anyway you want. And you don't have to manually pass it around with all method calls, as execution contexts are managed by the **[[Execution component>>http://maven.xwiki.org/site/xwiki-core-parent/xwiki-core-context/apidocs/org/xwiki/context/Execution.html]]**, which you can use just like any other XWiki component.
332 +<p/>
333 +In short, if you want to get access to the execution context (which holds context information inserted by the new components), you must declare a requirement on the ##Execution## component (located in the ##xwiki-core-context## module), and then you can write:
327 327  
328 -In the component world, the current request information is held in an *[execution context>http://maven.xwiki.org/site/xwiki-core-parent/xwiki-core-context/apidocs/org/xwiki/context/ExecutionContext.html]*. This is actually more powerful than the old XWiki context, as it is a generic execution context, and you can create one anytime you want and use it anyway you want. And you don't have to manually pass it around with all method calls, as execution contexts are managed by the *[Execution component>http://maven.xwiki.org/site/xwiki-core-parent/xwiki-core-context/apidocs/org/xwiki/context/Execution.html]*, which you can use just like any other XWiki component.
329 -
330 -In short, if you want to get access to the execution context (which holds context information inserted by the new components), you must declare a requirement on the <tt>Execution</tt> component (located in the <tt>xwiki-core-context</tt> module), and then you can write:
331 -{code}
332 - /** Provides access to the request context. Injected by the Component Manager. */
335 +{{code}}
336 +/** Provides access to the request context. Injected by the Component Manager. */
333 333   @Requirement
334 334   private Execution execution;
335 335  
... ... @@ -340,33 +340,33 @@
340 340   ExecutionContext context = execution.getContext();
341 341   // Do something with the execution context
342 342   }
343 -{code}
347 +{{/code}}
344 344  
345 -If you still need to access the old XWiki context, then you can get a reference to it from the execution context, but you should not cast it to an <tt>XWikiContext</tt>, which would pull the whole xwiki-core as a dependency, but to a <tt>Map</tt>. You won't be able to access all the properties, like the current user name or the URL factory, but you can access anything placed in the internal map of the XWikiContext.
346 -{code}
347 - private void workWithTheContext()
349 +If you still need to access the old XWiki context, then you can get a reference to it from the execution context, but you should not cast it to an ##XWikiContext##, which would pull the whole xwiki-core as a dependency, but to a ##Map##. You won't be able to access all the properties, like the current user name or the URL factory, but you can access anything placed in the internal map of the XWikiContext.
350 +
351 +{{code}}
352 +private void workWithTheContext()
348 348   {
349 349   ExecutionContext context = execution.getContext();
350 350   Map<Object, Object> xwikiContext = (Map<Object, Object>) context.getProperty("xwikicontext");
351 351   // Do something with the XWiki context
352 352   }
353 -{code}
358 +{{/code}}
354 354  
355 -If you want not just to use the execution context, but to make something available in every execution context, you can create an implementation of the [ExecutionContextInitializer>http://maven.xwiki.org/site/xwiki-core-parent/xwiki-core-context/apidocs/org/xwiki/context/ExecutionContextInitializer.html] component, and populate newly created execution contexts, just like with [velocity contexts>#HAccessingacomponentfromvelocity].
360 +If you want not just to use the execution context, but to make something available in every execution context, you can create an implementation of the [[ExecutionContextInitializer>>http://maven.xwiki.org/site/xwiki-core-parent/xwiki-core-context/apidocs/org/xwiki/context/ExecutionContextInitializer.html]] component, and populate newly created execution contexts, just like with [[velocity contexts>>#HAccessingacomponentfromvelocity]].
356 356  
357 -1.1.1 Code outside components
362 +=== Code outside components ===
358 358  
359 -You can use external libraries as in any other maven module, just declare the right dependencies in your module's <tt>pom.xml</tt>.
360 -
361 -As a general rule, you should *not* work with any non-componentized XWiki code, as the way the old code was designed leads to an eventual dependency on the whole <tt>xwiki-core</tt> module, which we are trying to avoid. If the component you are writing is needed by other modules (which is the case with most components, since a component which isn't providing any usable/used services is kind of useless), then this will likely lead to an eventual cyclic dependency, which will break the whole build.
362 -
363 -If you need some functionality from the old core, consider rewriting that part as a new component first, and then use that new component from your code. You should ask first on the [devs mailing list>dev:Community.MailingLists], so that we can design and implement it collaboratively.
364 -
364 +You can use external libraries as in any other maven module, just declare the right dependencies in your module's ##pom.xml##.
365 +<p/>
366 +As a general rule, you should **not** work with any non-componentized XWiki code, as the way the old code was designed leads to an eventual dependency on the whole ##xwiki-core## module, which we are trying to avoid. If the component you are writing is needed by other modules (which is the case with most components, since a component which isn't providing any usable/used services is kind of useless), then this will likely lead to an eventual cyclic dependency, which will break the whole build.
367 +<p/>
368 +If you need some functionality from the old core, consider rewriting that part as a new component first, and then use that new component from your code. You should ask first on the [[devs mailing list>>dev:Community.MailingLists]], so that we can design and implement it collaboratively.
369 +<p/>
365 365  If the effort needed for this is too large, you can try creating a bridge component, by writing just the interfaces in a new module, and make the classes from the core the default implementation of those interfaces. Then, since in the end the xwiki-core, the bridge component and your component will reside in the same classpath, plexus will take care of coupling the right classes. Be careful when writing such bridges, as they are short lived (since in the end all the old code will be replaced by proper components), and if the future real component will have a different interface, then you will have to rewrite your code to adapt to the new method names, or worse, the new component logic.
366 366  
367 -1.1 Deploying and using the component
372 +== Deploying and using the component ==
368 368  
369 369  In order to have your component work with XWiki, build the maven module, and find the produced <b>.jar</b> in the target folder. Copy this .jar to the <b>/WEB-INF/lib</b> folder of your wiki instance, restart the servlet container and you're done: you should be able to access your component from velocity or groovy code, and other potential components depending on it should be able to look it up.
370 -
371 -
372 -
375 +{{/html}}
376 +{{/velocity}}
XWiki.XWikiComments[3]
Date
... ... @@ -1,1 +1,1 @@
1 -2010-02-12 02:22:24.965
1 +2010-02-12 02:22:24.0

Get Connected