Changes for page Wiki Component API

Last modified by Admin on 2024/04/18 06:46

From version 2.1
edited by Jean-Vincent Drean
on 2012/09/14 16:39
Change comment: There is no comment for this version
To version 3.1
edited by Jean-Vincent Drean
on 2012/09/14 16:41
Change comment: There is no comment for this version

Summary

Details

EXOExtensionCode.ExtensionClass[0]
Bundled With
... ... @@ -1,0 +1,1 @@
1 +enterprise
ExtensionCode.ExtensionClass[0]
Authors
... ... @@ -1,1 +1,1 @@
1 -xwiki:XWiki.jvdrean
1 +xwiki:XWiki.XWikiTeam
Description
... ... @@ -1,0 +1,318 @@
1 +== Introduction ==
2 +
3 +Introduced in XWiki 4.2, the wiki component module is a bridge between [[XWiki java components>>platform:DevGuide.WritingComponents]] and wiki documents. The module has 2 main features:
4 +1. Easily bind a java component to a document through a mechanism re-instantiating the java component each time the corresponding document is modified. This allows the component to rely on information or even scripts stored in the wiki.
5 +1. Write components directly within documents, using XObjects. Those compoments will be considered similar to components written in Java by the rest of the platform.
6 +
7 +== Bind component implementations to documents ==
8 +
9 +When implementations of a component are defined (or at least of part of them) in documents what we did was:
10 +
11 +* Search for all the implementations within the wiki, usually through a [[query>>extensions:Extension.Query Module]] looking for XObjects of a specific XClass.
12 +* Create a component descriptor for each implementation found
13 +* Register each implementation
14 +* Set up a listener, to listen to:
15 +** document creations and modifications, to unregister and register the implementations they contain, if any
16 +** document deletions, to unregister implementations they contain, if any
17 +
18 +The wiki component modules removes the need for some of those steps, to use it your component role must extend the ##WikiComponent## Interface
19 +
20 +{{code language="java"}}
21 +/**
22 + * Represents the definition of a wiki component implementation. A java component can extend this interface if it needs
23 + * to be bound to a document, in order to be unregistered and registered again when the document is modified, and
24 + * unregistered when the document is deleted.
25 + *
26 + * @version $Id: 406ebb4a913d7bbe9cb5f2297152c9afd9efc9a2 $
27 + * @since 4.2M3
28 + */
29 +public interface WikiComponent
30 +{
31 + /**
32 + * Get the reference of the document this component instance is bound to.
33 + *
34 + * @return the reference to the document holding this wiki component definition.
35 + */
36 + DocumentReference getDocumentReference();
37 +
38 + /**
39 + * @return the role implemented by this component implementation.
40 + */
41 + Class< ? > getRole();
42 +
43 + /**
44 + * @return the hint of the role implemented by this component implementation.
45 + */
46 + String getRoleHint();
47 +
48 + /**
49 + * Get the list of interfaces the wiki component implements, apart from its main Role. When the component is
50 + * entirely written in a document, it allows the {@link WikiComponentManager} to add those Interfaces to the list of
51 + * implemented interfaces of the {@link java.lang.reflect.Proxy} it will create.
52 + * Classes extending this interface only need to return an empty list here since the list of interfaces they
53 + * implement will be determined using Java reflection.
54 + *
55 + * @return the extra list of interfaces this component implementation implements.
56 + */
57 + List<Class< ? >> getImplementedInterfaces();
58 +
59 + /**
60 + * Get the implementations of all the methods the component handles. It allows to write method implementations in
61 + * wiki documents, using script macros. When a method has multiple signatures (different sets of parameters) the
62 + * same {@link XDOM} will be executed.
63 + * Classes extending this interface only need to return an empty list here since the methods they handle are native
64 + * Java methods.
65 + *
66 + * @return the map of method name/wiki code this component implementation handles.
67 + */
68 + Map<String, XDOM> getHandledMethods();
69 +}
70 +{{/code}}
71 +
72 +[[View on github>>https://github.com/xwiki/xwiki-platform/blob/master/xwiki-platform-core/xwiki-platform-component/xwiki-platform-component-wiki/src/main/java/org/xwiki/component/wiki/WikiComponent.java]]
73 +
74 +Once your component extends the Interface above you need to provide a component builder implementing the following interface:
75 +
76 +{{code language="java"}}
77 +/**
78 + * Allows to provide a list of documents holding one or more {@link WikiComponent}, and to build components from those
79 + * documents.
80 + *
81 + * @version $Id: 9d1ae83dc1970909a991ccf0a216809c0ddee30a $
82 + * @since 4.2M3
83 + */
84 +@Role
85 +public interface WikiComponentBuilder
86 +{
87 + /**
88 + * Get the list of documents holding components.
89 + *
90 + * @return the list of documents holding components
91 + */
92 + List<DocumentReference> getDocumentReferences();
93 +
94 + /**
95 + * Build the components defined in a document XObjects. Being able to define more than one component in a document
96 + * depends on the implementation. It is up to the implementation to determine if the last author of the document
97 + * has the required permissions to register a component.
98 + *
99 + * @param reference the reference to the document that holds component definition objects
100 + * @return the constructed component definition
101 + * @throws WikiComponentException when the document contains invalid component definition(s)
102 + */
103 + List<WikiComponent> buildComponents(DocumentReference reference) throws WikiComponentException;
104 +}
105 +{{/code}}
106 +
107 +[[View on github>>https://github.com/xwiki/xwiki-platform/blob/master/xwiki-platform-core/xwiki-platform-component/xwiki-platform-component-wiki/src/main/java/org/xwiki/component/wiki/WikiComponentBuilder.java]]
108 +
109 +When this is done, every time a document holding information about one of your component implementations is modified ###buildComponents(DocumentReference)## will be called, allowing you to rebuild the component bound to it. You will find an example of implementation below.
110 +
111 +=== Example of WikiComponent implementation ===
112 +
113 +We will make a very simple component for this example, Proverb. As seen above, this component Role extends WikiComponent.
114 +
115 +{{code language="java"}}
116 +package org.xwiki.example;
117 +
118 +import org.xwiki.component.annotation.Role;
119 +import org.xwiki.component.wiki.WikiComponent;
120 +
121 +@Role
122 +public interface Proverb extends WikiComponent
123 +{
124 + /**
125 + * @return A proverb
126 + */
127 + String get();
128 +}
129 +{{/code}}
130 +
131 +We write a class implementing this new Role, this will be the **bridge** between components and the wiki:
132 +
133 +{{code language="java"}}
134 +package org.xwiki.example.internal;
135 +
136 +import java.util.List;
137 +import java.util.Map;
138 +
139 +import org.apache.commons.collections.ListUtils;
140 +import org.apache.commons.collections.MapUtils;
141 +import org.xwiki.example.Proverb;
142 +import org.xwiki.model.reference.DocumentReference;
143 +import org.xwiki.rendering.block.XDOM;
144 +
145 +public class WikiProverb implements Proverb
146 +{
147 + private DocumentReference reference;
148 +
149 + private String proverb;
150 +
151 + private String hint;
152 +
153 + public WikiProverb(DocumentReference reference, String hint, String proverb)
154 + {
155 + this.reference = reference;
156 + this.hint = hint;
157 + this.proverb = proverb;
158 + }
159 +
160 + @Override
161 + public String get()
162 + {
163 + return proverb;
164 + }
165 +
166 + @Override
167 + public DocumentReference getDocumentReference()
168 + {
169 + return reference;
170 + }
171 +
172 + @Override
173 + public Class<?> getRole()
174 + {
175 + return Proverb.class;
176 + }
177 +
178 + @Override
179 + public String getRoleHint()
180 + {
181 + return hint;
182 + }
183 +
184 + @Override
185 + public List<Class<?>> getImplementedInterfaces()
186 + {
187 + return ListUtils.EMPTY_LIST;
188 + }
189 +
190 + @Override
191 + public Map<String, XDOM> getHandledMethods()
192 + {
193 + return MapUtils.EMPTY_MAP;
194 + }
195 +}
196 +{{/code}}
197 +
198 +And now we need a builder:
199 +
200 +{{code language="java"}}
201 +package org.xwiki.example.internal;
202 +
203 +import java.util.ArrayList;
204 +import java.util.List;
205 +
206 +import javax.inject.Inject;
207 +import javax.inject.Named;
208 +import javax.inject.Singleton;
209 +
210 +import org.xwiki.component.annotation.Component;
211 +import org.xwiki.component.wiki.WikiComponent;
212 +import org.xwiki.component.wiki.WikiComponentBuilder;
213 +import org.xwiki.component.wiki.WikiComponentException;
214 +import org.xwiki.context.Execution;
215 +import org.xwiki.model.reference.DocumentReference;
216 +import org.xwiki.model.reference.EntityReferenceSerializer;
217 +import org.xwiki.query.Query;
218 +import org.xwiki.query.QueryManager;
219 +
220 +import com.xpn.xwiki.XWikiContext;
221 +import com.xpn.xwiki.doc.XWikiDocument;
222 +import com.xpn.xwiki.objects.BaseObject;
223 +
224 +@Component
225 +@Singleton
226 +@Named("proverb")
227 +public class WikiProverbBuilder implements WikiComponentBuilder
228 +{
229 + @Inject
230 + private Execution execution;
231 +
232 + @Inject
233 + private QueryManager queryManager;
234 +
235 + @Inject
236 + private EntityReferenceSerializer<String> serializer;
237 +
238 + @Override
239 + public List<DocumentReference> getDocumentReferences()
240 + {
241 + List<DocumentReference> references = new ArrayList<DocumentReference>();
242 +
243 + try {
244 + Query query =
245 + queryManager.createQuery("select doc.space, doc.name from Document doc, doc.object(XWiki.Proverb) "
246 + + "as proverb where proverb.proverb <> ''",
247 + Query.XWQL);
248 + List<Object[]> results = query.execute();
249 + for (Object[] result : results) {
250 + references.add(
251 + new DocumentReference(getXWikiContext().getDatabase(), (String) result[0], (String) result[1]));
252 + }
253 + } catch (Exception e) {
254 + // Fail "silently"
255 + e.printStackTrace();
256 + }
257 +
258 + return references;
259 + }
260 +
261 + @Override
262 + public List<WikiComponent> buildComponents(DocumentReference reference) throws WikiComponentException
263 + {
264 + List<WikiComponent> components = new ArrayList<WikiComponent>();
265 + DocumentReference proverbXClass = new DocumentReference(getXWikiContext().getDatabase(), "XWiki", "Proverb");
266 +
267 + try {
268 + XWikiDocument doc = getXWikiContext().getWiki().getDocument(reference, getXWikiContext());
269 + for (BaseObject obj : doc.getXObjects(proverbXClass)) {
270 + String roleHint = serializer.serialize(obj.getReference());
271 + components.add(new WikiProverb(reference, roleHint, obj.getStringValue("proverb")));
272 + }
273 + } catch (Exception e) {
274 + throw new WikiComponentException(String.format("Failed to build Proverb components from document [%s]",
275 + reference.toString()), e);
276 + }
277 +
278 + return components;
279 + }
280 +
281 + private XWikiContext getXWikiContext()
282 + {
283 + return (XWikiContext) this.execution.getContext().getProperty("xwikicontext");
284 + }
285 +}
286 +{{/code}}
287 +
288 +Voila! Once the JAR is dropped within xwiki/WEB-INF/lib/ it's possible to create components from the wiki, to do so you need to:
289 +
290 +1. Create the XWiki.Proverb class, by adding a ##String## property named ##proverb## to it (((
291 +
292 +{{image reference="WikiComponent-Step1.png" /}}
293 +)))
294 +
295 +1. Create objects from that class, in one or multiple documents (((
296 +
297 +{{image reference="WikiComponent-Step2.png" /}}
298 +)))
299 +
300 +1. You can now write a little script to retrieve your components (((
301 +
302 +{{code language="none"}}
303 +{{groovy}}
304 +
305 +import org.xwiki.example.Proverb;
306 +
307 +for (Proverb proverb : services.component.getComponentManager().getInstanceList(Proverb.class)) {
308 + println("* " + proverb.get())
309 +}
310 +
311 +{{/groovy}}
312 +{{/code}}
313 +)))
314 +
315 +1. You'll see the proverbs you created appear (((
316 +
317 +{{image reference="WikiComponent-Step3.png" /}}
318 +)))
Id
... ... @@ -1,1 +1,1 @@
1 -jvdrean:wikicomponent-module
1 +xwiki:wikicomponent-module
Source
... ... @@ -1,0 +1,1 @@
1 +https://github.com/xwiki/xwiki-platform/tree/master/xwiki-platform-core/xwiki-platform-component/xwiki-platform-component-wiki
Summary
... ... @@ -1,0 +1,1 @@
1 +Defines a way to develop components within documents, or to bind a component to a document

Get Connected