Wiki source code of Creating XWiki Components

Last modified by Simon Urli on 2023/10/10

Hide last authors
Thomas Mortagne 46.1 1 {{box cssClass="floatinginfobox" title="**Contents**"}}
2 {{toc/}}
3 {{/box}}
Anca Luca 1.1 4
Simon Urli 77.2 5 This tutorial guides you through the creation of a XWiki component, which is a way to extend or customize the XWiki platform. Indeed the XWiki platform is composed of components and it's possible to replace the default implementations with your own implementations. It's also possible to add new component implementations to extend the platform such as by implementing new [[Rendering Macros>>xwiki:Documentation.DevGuide.RenderingMacroTutorial]].
Anca Luca 1.1 6
Thomas Mortagne 46.1 7 {{info}}
Manuel Smeria 52.3 8 Components replace the older plugin architecture which has been deprecated a while ago.
Thomas Mortagne 46.1 9 {{/info}}
Vincent Massol 28.1 10
Vincent Massol 37.5 11 You should start by reading the [[Reference document on XWiki Components>>extensions:Extension.Component Module]].
Anca Luca 1.1 12
Silvia Macovei 27.1 13 = Let's get started! =
Anca Luca 1.1 14
15 Enough talking, let's see some code!
16
Manuel Smeria 52.3 17 In the following tutorial we will guide you through writing a simple component, helping you to quickly get oriented in the XWiki components world and explaining how it works.
Anca Luca 1.1 18
Vincent Massol 28.1 19 == Creating a XWiki component using Maven ==
Anca Luca 1.1 20
Sergei Kulagin 76.5 21 As you've read in the [[XWiki Component Reference>>extensions:Extension.Component Module]] writing a component is a three-steps process (component interface, component implementation and registration of component).
Silvia Macovei 26.1 22
Manuel Smeria 52.3 23 To make it easier for you to get started, we have created a [[Maven Archetype>>http://maven.apache.org/archetype/maven-archetype-plugin/]] to help create a simple component module with a single command.
Sergiu Dumitriu 37.2 24
Adel Atallah 71.2 25 After you've [[installed Maven>>http://maven.apache.org/]], open a shell prompt and type: {{code language="none"}}mvn archetype:generate{{/code}}.
Anca Luca 1.1 26
Vincent Massol 71.5 27 This will list all archetypes available on Maven Central. If instead you wish to directly use the XWiki Component Archetype, you can directly type (update the version to [[use the version you wish to use>>http://nexus.xwiki.org/nexus/content/groups/public/org/xwiki/commons/xwiki-commons-component-archetype/]]):
Vincent Massol 47.1 28
29 {{code language="none"}}
30 mvn archetype:generate \
31 -DarchetypeArtifactId=xwiki-commons-component-archetype \
32 -DarchetypeGroupId=org.xwiki.commons \
Vincent Massol 73.3 33 -DarchetypeVersion=11.10.5
Vincent Massol 47.1 34 {{/code}}
35
Vincent Massol 28.1 36 Then follow the instructions. For example:
Sergiu Dumitriu 37.2 37
Vincent Massol 28.2 38 {{code language="none"}}
Vincent Massol 28.1 39 [INFO] Scanning for projects...
40 [INFO]
41 [INFO] ------------------------------------------------------------------------
42 [INFO] Building Maven Stub Project (No POM) 1
43 [INFO] ------------------------------------------------------------------------
44 [INFO]
Vincent Massol 53.4 45 [INFO] >>> maven-archetype-plugin:2.2:generate (default-cli) @ standalone-pom >>>
Vincent Massol 28.1 46 [INFO]
Vincent Massol 53.4 47 [INFO] <<< maven-archetype-plugin:2.2:generate (default-cli) @ standalone-pom <<<
Vincent Massol 28.1 48 [INFO]
Vincent Massol 53.4 49 [INFO] --- maven-archetype-plugin:2.2:generate (default-cli) @ standalone-pom ---
Vincent Massol 28.1 50 [INFO] Generating project in Interactive mode
Vincent Massol 53.4 51 [INFO] Archetype repository missing. Using the one from [org.xwiki.commons:xwiki-commons-component-archetype:6.1-milestone-1] found in catalog remote
Vincent Massol 28.1 52 Define value for property 'groupId': : com.acme
Vincent Massol 53.4 53 Define value for property 'artifactId': : example
Vincent Massol 28.1 54 Define value for property 'version': 1.0-SNAPSHOT: :
55 Define value for property 'package': com.acme: :
56 Confirm properties configuration:
57 groupId: com.acme
58 artifactId: example
59 version: 1.0-SNAPSHOT
60 package: com.acme
61 Y: : Y
62 [INFO] ----------------------------------------------------------------------------
Vincent Massol 53.4 63 [INFO] Using following parameters for creating project from Archetype: xwiki-commons-component-archetype:5.4.4
Vincent Massol 28.1 64 [INFO] ----------------------------------------------------------------------------
65 [INFO] Parameter: groupId, Value: com.acme
Vincent Massol 47.1 66 [INFO] Parameter: artifactId, Value: example
67 [INFO] Parameter: version, Value: 1.0-SNAPSHOT
Vincent Massol 28.1 68 [INFO] Parameter: package, Value: com.acme
Vincent Massol 47.1 69 [INFO] Parameter: packageInPathFormat, Value: com/acme
70 [INFO] Parameter: package, Value: com.acme
71 [INFO] Parameter: version, Value: 1.0-SNAPSHOT
72 [INFO] Parameter: groupId, Value: com.acme
Vincent Massol 28.1 73 [INFO] Parameter: artifactId, Value: example
Vincent Massol 47.1 74 [INFO] project created from Archetype in dir: /private/tmp/example
Vincent Massol 28.1 75 [INFO] ------------------------------------------------------------------------
76 [INFO] BUILD SUCCESS
77 [INFO] ------------------------------------------------------------------------
Vincent Massol 53.4 78 [INFO] Total time: 25.019s
79 [INFO] Finished at: Thu May 29 18:49:46 CEST 2014
80 [INFO] Final Memory: 11M/26M
Vincent Massol 28.1 81 [INFO] ------------------------------------------------------------------------
Vincent Massol 28.2 82 {{/code}}
Anca Luca 1.1 83
Vincent Massol 28.2 84 Then go in the created directory (##example## in our example above) and run ##mvn install## to build your component.
Anca Luca 1.1 85
Vincent Massol 29.1 86 == The Component explained ==
Silvia Macovei 27.1 87
Vincent Massol 29.1 88 Assume, for the following explanations, that the package you used is ##com.acme##
Silvia Macovei 26.1 89
Vincent Massol 29.1 90 Navigating in the component project folder, you will see the following standard Maven project structure:
Silvia Macovei 26.1 91
Vincent Massol 30.1 92 {{code language="none"}}
Anca Luca 1.1 93 pom.xml
Vincent Massol 29.1 94 src/main/java/com/acme/HelloWorld.java
95 src/main/java/com/acme/internal/DefaultHelloWorld.java
Vincent Massol 33.1 96 src/main/java/com/acme/internal/HelloWorldScriptService.java
dan 19.1 97 src/main/resources/META-INF/components.txt
Vincent Massol 29.1 98 src/test/java/com/acme/HelloWorldTest.java
Silvia Macovei 26.1 99 {{/code}}
Anca Luca 1.1 100
Manuel Smeria 52.3 101 which corresponds to the default files created: the ##HelloWorld## interface (a.k.a component role), its implementation ##DefaultHelloWorld## (component implementation), a test class for this component ##HelloWorldTest##, the component declaration file ##components.txt## and the Maven project ##pom.xml## file. The ##HelloWorldScriptService## file is described below when we explain how to make the component's API available to wiki pages.
Silvia Macovei 26.1 102
Manuel Smeria 52.3 103 If you have a look in ##pom.xml## you'll notice the following dependencies:
Silvia Macovei 26.1 104
Vincent Massol 30.1 105 {{code language="xml"}}
Vincent Massol 29.1 106 <dependencies>
Anca Luca 1.1 107 <dependency>
Vincent Massol 44.3 108 <groupId>org.xwiki.commons</groupId>
Thomas Mortagne 45.1 109 <artifactId>xwiki-commons-component-api</artifactId>
Vincent Massol 44.3 110 <version>${commons.version}</version>
Anca Luca 1.1 111 </dependency>
Vincent Massol 29.1 112 <!-- Testing dependencies -->
Anca Luca 1.1 113 <dependency>
Vincent Massol 44.3 114 <groupId>org.xwiki.commons</groupId>
115 <artifactId>xwiki-commons-test</artifactId>
116 <version>${commons.version}</version>
Anca Luca 1.1 117 <scope>test</scope>
Vincent Massol 29.1 118 </dependency>
Anca Luca 1.1 119 </dependencies>
Silvia Macovei 26.1 120 {{/code}}
Silvia Macovei 27.1 121
Thomas Mortagne 46.1 122 The code above defines the dependency on the ##xwiki-core-component-api## in the core which is where XWiki Component notions are defined. There's also a dependency on ##xwiki-core-shared-tests## which provides helper classes to easily test components.
Anca Luca 1.1 123
Manuel Smeria 52.3 124 The interface file (##HelloWorld.java##) contains the definition of a regular Java interface and looks like this:
Silvia Macovei 26.1 125
Vincent Massol 30.1 126 {{code language="java"}}
Denis Gervalle 52.4 127 @Role /* annotation used for declaring the service our component provides */
dan 19.1 128 public interface HelloWorld
129 {
130 String sayHello();
131 }
Silvia Macovei 26.1 132 {{/code}}
Anca Luca 1.1 133
Vincent Massol 29.1 134 Keep in mind that this interface specifies the API that other components can use on your component. In our case, we'll build a polite component that can ##sayHello()##.
Silvia Macovei 27.1 135
Sorin Burjan 42.3 136 Then we have the implementation of the interface, the ##DefaultHelloWorld## class.
Oana Florea 23.1 137
Thomas Mortagne 46.1 138 {{code language="java"}}
Vincent Massol 29.1 139 @Component /* annotation used for declaring a component implementation */
Vincent Massol 44.1 140 @Singleton /* annotation used for defining the component as a singleton */
Vincent Massol 29.1 141 public class DefaultHelloWorld implements HelloWorld
Silvia Macovei 26.1 142 {{/code}}
dan 19.1 143
mkozakov 59.1 144 Note that optionally, there is a ##@Named## annotation to specify a component //hint//. This is useful especially when we want to distinguish between several implementations for the same type of component. Imagine we had a special HelloWorld implementation taking the greeting message from a database; it could look like:
Silvia Macovei 26.1 145
Thomas Mortagne 46.1 146 {{code language="java"}}
Vincent Massol 44.1 147 @Component
148 @Named("database")
Vincent Massol 29.1 149 public class DatabaseHelloWorld implements HelloWorld
Silvia Macovei 26.1 150 {{/code}}
Silvia Macovei 27.1 151
Vincent Massol 29.1 152 Then the ##sayHello## in ##DefaultHelloWorld## is basic in this example:
Silvia Macovei 26.1 153
Vincent Massol 30.1 154 {{code language="java"}}
dan 19.1 155 /**
156 * Says hello by returning a greeting to the caller.
157 *
158 * @return A greeting.
159 */
160 public String sayHello()
161 {
162 return "Hello world!";
163 }
Silvia Macovei 26.1 164 {{/code}}
Anca Luca 1.1 165
poppakap 53.1 166 And now, the ##components.txt## file, in which component implementations present in this jar are specified for the ##ComponentManager## to register them.
Anca Luca 1.1 167
Thomas Mortagne 46.1 168 {{code language="none"}}
169 com.acme.internal.DefaultHelloWorld
170 {{/code}}
Anca Luca 1.1 171
Silvia Macovei 27.1 172 = How to find my component and use it? =
Anca Luca 24.1 173
Silvia Macovei 27.1 174 == From other components ==
Anca Luca 1.1 175
Gabriela Smeria 57.1 176 To access your component from another component we use the components engine, and specify the dependencies, leaving instantiation and component injection to be handled by the component manager.
Silvia Macovei 27.1 177
Gabriela Smeria 58.1 178 In order to use the ##HelloWorld## component, you need a reference to it in the component that uses it. For this, you should 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:
Silvia Macovei 27.1 179
Silvia Macovei 26.1 180 {{code}}
dan 19.1 181 @Component
Vincent Massol 44.1 182 @Singleton
Vincent Massol 30.1 183 public class DefaultSocializer implements Socializer
Anca Luca 1.1 184 {
185 [...]
186
187 /** Will be injected by the component manager */
Vincent Massol 44.1 188 @Inject
Anca Luca 1.1 189 private HelloWorld helloWorld;
190
Thomas Mortagne 52.1 191 /** Will be injected by the component manager */
192 @Inject
193 @Named("database")
194 private HelloWorld databaseWorld;
195
Anca Luca 1.1 196 [...]
197 }
Silvia Macovei 26.1 198 {{/code}}
Anca Luca 1.1 199
Vincent Massol 44.1 200 Note the ##@Inject## annotation, which instructs the component manager to inject the required component where needed.
Silvia Macovei 27.1 201
Silvia Macovei 26.1 202 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:
Anca Luca 1.1 203
Silvia Macovei 26.1 204 {{code}}
Vincent Massol 30.1 205 public class DefaultSocializer implements Socializer
Anca Luca 1.1 206 {
207 [...]
208
209 public void startConversation()
210 {
211 this.helloWorld.sayHello();
212
213 [...]
214 }
215
216 [...]
217 }
Silvia Macovei 26.1 218 {{/code}}
Anca Luca 1.1 219
Silvia Macovei 26.1 220 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.
Silvia Macovei 27.1 221
222 == From non-components java code (e.g. older plugins) ==
Anca Luca 1.1 223
Vincent Massol 31.1 224 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. The ##getComponent## function also has a signature without the ##hint## parameter, that uses the default hint.
Vincent Massol 30.2 225
Vincent Massol 31.1 226 To use our greetings provider component, we would simply invoke:
Silvia Macovei 27.1 227
Silvia Macovei 26.1 228 {{code}}
Vincent Massol 31.1 229 HelloWorld greeter = Utils.getComponent(HelloWorld.class);
Anca Luca 1.1 230 greeter.sayHello();
Thomas Mortagne 52.1 231
232 HelloWorld databaseGreeter = Utils.getComponent(HelloWorld.class, "database");
233 greeter.sayHello();
Silvia Macovei 26.1 234 {{/code}}
Anca Luca 1.1 235
Manuel Smeria 52.3 236 {{warning}}
237 Even if 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.
238 {{/warning}}
Silvia Macovei 27.1 239
Manuel Smeria 52.3 240 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.
241
Thomas Mortagne 46.1 242 {{info}}
243 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 as described in the [[Component Module Reference>>extensions:Extension.Component Module]].
244 {{/info}}
Anca Luca 1.1 245
Silvia Macovei 27.1 246 == From wiki pages ==
Anca Luca 15.1 247
Manuel Smeria 52.3 248 Components can be made accessible to wiki pages by writing a ##ScriptService## implementation. They can then be accessed using any provided scripting language (velocity, groovy, python, ruby, php, etc).
Anca Luca 1.1 249
Vincent Massol 32.1 250 Let's make our ##sayHello## method accessible:
251
252 {{code language="java"}}
Vincent Massol 44.1 253 @Component
254 @Named("hello")
255 @Singleton
Vincent Massol 32.1 256 public class HelloWorldScriptService implements ScriptService
257 {
Vincent Massol 44.1 258 @Inject
Vincent Massol 32.1 259 private HelloWorld helloWorld;
260
261 public String greet()
262 {
263 return this.helloWorld.sayHello();
264 }
265 }
266 {{/code}}
267
Vincent Massol 53.2 268 Note: We could have also injected the Named component instead, "database" which would look like:
269
Vincent Massol 63.3 270 {{code language="java"}}
Vincent Massol 63.2 271 // Or inject a Named Component
272 @Inject
273 @Named("database")
274 private HelloWorld databaseWorld;
275 {{/code}}
poppakap 53.1 276
Manuel Smeria 52.3 277 {{info}}
278 The component hint used (the ##hello## part in the ##@Component##) is the name under which the script service will be accessible from scripting languages.
279 {{/info}}
Vincent Massol 32.1 280
Thomas Mortagne 67.1 281 For example to access it in Velocity you'd write:
Vincent Massol 32.1 282
Vincent Massol 71.3 283 {{code language="none"}}
284 {{velocity}}
Thomas Mortagne 67.1 285 $services.hello.greet()
Vincent Massol 71.3 286 {{/velocity}}
287 {{/code}}
Vincent Massol 32.1 288
Thomas Mortagne 67.1 289 From Groovy:
290
Vincent Massol 71.3 291 {{code language="none"}}
292 {{groovy}}
Thomas Mortagne 69.1 293 print services.hello.greet()
Vincent Massol 71.3 294 {{/groovy}}
295 {{/code}}
Thomas Mortagne 67.1 296
Vincent Massol 34.1 297 Now for our script service to work we need to register it as a component and thus add it to the ##META-INF/components.txt## file:
Vincent Massol 32.1 298
Manuel Smeria 52.3 299 {{code language="none"}}
300 ...
301 com.acme.internal.HelloWorldScriptService
302 {{/code}}
303
Vincent Massol 33.1 304 We also need to make the Script Service infrastructure available in our classpath. This is done by adding the following in your ##pom.xml## file:
Manuel Smeria 52.3 305
306 {{code language="xml"}}
307 <dependency>
Vincent Massol 44.3 308 <groupId>org.xwiki.commons</groupId>
309 <artifactId>xwiki-commons-script</artifactId>
310 <version>${commons.version}</version>
Manuel Smeria 52.3 311 </dependency>
312 {{/code}}
Vincent Massol 33.1 313
Vincent Massol 35.1 314 = Accessing Legacy code =
Anca Luca 1.1 315
Vincent Massol 35.1 316 By legacy we mean old XWiki code that hasn't been moved to components yet.
Anca Luca 1.1 317
Silvia Macovei 27.1 318 == The XWiki data model ==
Anca Luca 1.1 319
Vincent Massol 76.2 320 Since the XWiki data model (documents, objects, attachments, etc.) reside in the big, old ##xwiki-platform-oldcore## 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-platform-oldcore##.
Silvia Macovei 27.1 321
Vincent Massol 76.2 322 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 declare the classes in ##xwiki-platform-oldcore## as the default implementation for those components.
Silvia Macovei 27.1 323
Vincent Massol 76.2 324 If your component needs to access the XWiki data model, it will use the components from the ##xwiki-platform-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 [[Forum>>dev:Community.Discuss]].
Silvia Macovei 27.1 325
Silvia Macovei 26.1 326 For example:
Anca Luca 1.1 327
Silvia Macovei 26.1 328 {{code}}
dan 19.1 329 @Component
Vincent Massol 44.1 330 @Singleton
Anca Luca 1.1 331 public class DefaultHelloWorld implements HelloWorld
332 {
333 /** Provides access to documents. Injected by the Component Manager. */
Vincent Massol 44.1 334 @Inject
Anca Luca 1.1 335 private DocumentAccessBridge documentAccessBridge;
336
337 [...]
338
339 private String getConfiguredGreeting()
340 {
341 return documentAccessBridge.getProperty("XWiki.XWikiPreferences", "greeting_text");
342 }
Silvia Macovei 26.1 343 {{/code}}
Anca Luca 1.1 344
slauriere 49.1 345 === Querying the data model ===
346
347 Queries can be performed by using an instance of a QueryManager, which can be obtained and used as follows :
348
349 {{code}}
350 QueryManager queryManager = (QueryManager) componentManager.getInstance(QueryManager.class);
351 Query query = queryManager.createQuery(xwqlstatement,Query.HQL);
352 List<Object> results = query.execute();
353 {{/code}}
354
Manuel Smeria 52.3 355 {{info}}
356 A reference to a ComponentManager can be obtained through injection, as explained on the [[Component module extension page>>extensions:Extension.Component Module#HGettingaccesstotheComponentManager]].
357 {{/info}}
slauriere 51.1 358
Silvia Macovei 27.1 359 == The XWiki context ==
Anca Luca 1.1 360
slauriere 76.4 361 Note that the XWiki context is in the process of getting 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.
Silvia Macovei 27.1 362
Mohammad Humayun Khan 76.1 363 In the component world, the current request information is held in an **{{scm project="xwiki-commons" path="xwiki-commons-core/xwiki-commons-context/src/main/java/org/xwiki/context/ExecutionContext.java"}}Execution Context{{/scm}}**. This is actually more powerful than the old XWikiContext, as it is a generic execution context, held in a ThreadLocal variable, 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 **{{scm project="xwiki-commons" path="xwiki-commons-core/xwiki-commons-context/src/main/java/org/xwiki/context/Execution.java"}}Execution{{/scm}}** component, which you can use just like any other XWiki component.
Silvia Macovei 27.1 364
slauriere 48.1 365 In short, if you want to get access to the execution context (which holds context information inserted by the new components), you must declare an injection point on the ##Execution## component (located in the ##xwiki-commons-context## module), and then you can write:
Anca Luca 1.1 366
Thomas Mortagne 63.1 367 {{code language="java"}}
Silvia Macovei 26.1 368 /** Provides access to the request context. Injected by the Component Manager. */
Vincent Massol 60.2 369 @Inject
370 private Execution execution;
371 ...
372 private void workWithTheContext()
373 {
374 ExecutionContext context = execution.getContext();
375 // Do something with the execution context
376 }
Silvia Macovei 26.1 377 {{/code}}
Anca Luca 1.1 378
Vincent Massol 60.1 379 All that said, we're still in a transition phase and a lot of information is still available only through the old XWikiContext and has not yet been moved to the ExecutioncContext (the current user for example just to mention one). Thus you may still need to access the old XWiki Context. You can get a reference to it from the Execution Context. If you can you should try to not cast it to an ##XWikiContext##, which would pull the whole ##xwiki-platform-oldcore## as a dependency, but to a ##Map##. Doing it this way, 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.
Silvia Macovei 26.1 380
Thomas Mortagne 63.1 381 {{code language="java"}}
Silvia Macovei 26.1 382 private void workWithTheContext()
Vincent Massol 60.1 383 {
384 ExecutionContext context = execution.getContext();
385 Map<Object, Object> xwikiContext = (Map<Object, Object>) context.getProperty("xwikicontext");
386 // Do something with the XWiki context
387 }
Silvia Macovei 26.1 388 {{/code}}
Anca Luca 1.1 389
Thomas Mortagne 62.1 390 If you need to access typed information then the easiest is to use a Provider the following way:
Anca Luca 1.1 391
Thomas Mortagne 62.1 392 {{code language="java"}}
Vincent Massol 60.1 393 @Inject
Thomas Mortagne 62.1 394 private Provider<XWikiContext> xwikiContextProvider;
Vincent Massol 60.1 395 ...
Thomas Mortagne 62.1 396 XWikiContext xcontext = this.xwikiContextProvider.get();
Vincent Massol 60.1 397 {{/code}}
398
slauriere 76.3 399 which will always provide a usable XWikiContext (if there is none in the current ExecutionContext it will create one), except in special cases where there is no ExecutionContext in the current thread, or if XWiki was not fully initialized yet.
Vincent Massol 61.1 400
Thomas Mortagne 62.1 401 Since 7.2 if you just want to get one if there is one (i.e. you don't need to automatically create a new one) you can use the "readonly" XWikiContext Provider as in:
402
Vincent Massol 61.1 403 {{code language="java"}}
404 @Inject
Thomas Mortagne 62.1 405 @Named("readonly")
Vincent Massol 61.1 406 private Provider<XWikiContext> xwikiContextProvider;
407 ...
408 XWikiContext xcontext = this.xwikiContextProvider.get();
Thomas Mortagne 62.1 409 if (xcontext != null) {
410 ...
411 }
Vincent Massol 61.1 412 {{/code}}
413
Simon Urli 77.2 414 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 **{{scm project="xwiki-commons" path="xwiki-commons-core/xwiki-commons-context/src/main/java/org/xwiki/context/ExecutionContextInitializer.java"}}ExecutionContextInitializer{{/scm}}** component, and populate newly created execution contexts, just like with [[velocity contexts>>#HFromwikipages]].
Vincent Massol 60.1 415
Silvia Macovei 27.1 416 == Code outside components ==
Anca Luca 1.1 417
Silvia Macovei 26.1 418 You can use external libraries as in any other maven module, just declare the right dependencies in your module's ##pom.xml##.
Silvia Macovei 27.1 419
Silvia Macovei 26.1 420 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.
Silvia Macovei 27.1 421
Sergei Kulagin 76.7 422 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. First, you should ask on the [[forum>>dev:Community.MailingLists]], so that we can design and implement it collaboratively.
Silvia Macovei 27.1 423
Anca Luca 1.1 424 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.
425
Vincent Massol 35.1 426 = Deploying the Component =
Anca Luca 1.1 427
Vincent Massol 77.1 428 Now that we have a functioning Component let's build it and deploy it to an XWiki instance. There are 2 ways but the recommended one is using the Extension Manager.
Thomas Mortagne 46.1 429
Vincent Massol 64.1 430 == Manually ==
431
Vincent Massol 32.1 432 * To build the component, issue ##mvn install##. This generates a JAR in the ##target## directory of your project.
Vincent Massol 73.1 433 * To install it into a XWiki instance, copy that JAR file, and **all its dependencies** in ##XWIKI_WAR_HOME/WEB-INF/lib## where ##XWIKI_WAR_HOME## is where the XWiki WAR is deployed.
Vincent Massol 32.1 434
Vincent Massol 64.1 435 == Using the Extension Manager ==
436
Vincent Massol 73.2 437 The advantage over the Manual way is that you don't need to care about dependencies nor regularly start/stop your XWiki instance and thus you don't incur the start wait times.
Vincent Massol 64.1 438
439 * Have a running XWiki instance configured with a local Extension Repository pointing to your Maven local Repository. Edit ##xwiki.properties## and make sure you have the following set:(((
Vincent Massol 64.2 440 {{code language="none"}}
Vincent Massol 64.1 441 extension.repositories=local:maven:file://${sys:user.home}/.m2/repository
442 extension.repositories=maven-xwiki:maven:http://nexus.xwiki.org/nexus/content/groups/public
443 extension.repositories=extensions.xwiki.org:xwiki:http://extensions.xwiki.org/xwiki/rest/
Vincent Massol 64.2 444 {{/code}}
Vincent Massol 64.1 445 )))
446 * Build your component and deploy it in your local Maven repository with ##mvn install##
Hassan Ali 74.1 447 * Inside your running XWiki instance, go to the Extension Manager in the Admin UI (e.g. ##{{{http://localhost:8080/xwiki/bin/admin/XWiki/XWikiPreferences?editor=globaladmin&section=XWiki.AddExtensions}}}##) and click on Advanced Search and enter your extension's id and version and follow the instructions. (##<groupId>:<artifactId>## , e.g: ##org.xwiki.contrib:your-extension-id##)
Vincent Massol 64.1 448
449 {{warning}}
Vincent Massol 77.1 450 If you want to redeploy an extension and it's already installed with the same version, the Extension Manager won't let you do so. Thus you'll need to do one of the following:
451 * Uninstall it using the Extension Manager and then remove the local version (which is kept even if uninstalled) using the [[Extension Tweak>>extensions:Extension.Extension Tweak]].
452 * If you're just testing, a simple solution is to increase the version number in the POM (e.g. if had deployed version ##1.0-SNAPSHOT##, you could increase the version to ##1.0.1-SNAPSHOT##, rebuild and redeploy). Then once you're happy that it works fine, put back the original version in your source tree.
Vincent Massol 64.1 453 {{/warning}}
454
Vincent Massol 32.1 455 Your component is now ready for service.
456
457 Enjoy!
slauriere 50.1 458
slauriere 51.1 459 = See also =
slauriere 50.1 460
461 * [[extensions:Extension.Component Module]]
Vincent Massol 56.2 462 * If you are experiencing problems trying to install the component using Maven, check the [[Building Guide>>dev:Community.Building]].

Get Connected