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
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
on 2012/09/14 16:41
Change comment:
There is no comment for this version
Summary
-
Objects (2 modified, 0 added, 0 removed)
Details
- EXOExtensionCode.ExtensionClass[0]
-
- Bundled With
-
... ... @@ -1,0 +1,1 @@ 1 +enterprise
- ExtensionCode.ExtensionClass[0]
-
- Authors
-
... ... @@ -1,1 +1,1 @@ 1 -xwiki:XWiki. jvdrean1 +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-module1 +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