On Sat, May 15, 2010 at 17:08, jvelociter
<contrib-notifications(a)xwiki.org> wrote:
>
> Author: jvelociter
> Date: 2010-05-15 17:08:25 +0200 (Sat, 15 May 2010)
> New Revision: 28878
>
> Added:
> Â contrib/sandbox/xwiki-wiki-components/
> Â contrib/sandbox/xwiki-wiki-components/pom.xml
> Â contrib/sandbox/xwiki-wiki-components/src/
> Â contrib/sandbox/xwiki-wiki-components/src/main/
> Â contrib/sandbox/xwiki-wiki-components/src/main/java/
> Â contrib/sandbox/xwiki-wiki-components/src/main/java/com/
> Â contrib/sandbox/xwiki-wiki-components/src/main/java/com/xpn/
> Â contrib/sandbox/xwiki-wiki-components/src/main/java/com/xpn/xwiki/
> Â contrib/sandbox/xwiki-wiki-components/src/main/java/com/xpn/xwiki/internal/
> Â contrib/sandbox/xwiki-wiki-components/src/main/java/com/xpn/xwiki/internal/DefaultWikiComponentBuilder.java
> Â contrib/sandbox/xwiki-wiki-components/src/main/java/com/xpn/xwiki/internal/WikiComponentInitializer.java
> Â contrib/sandbox/xwiki-wiki-components/src/main/java/org/
> Â contrib/sandbox/xwiki-wiki-components/src/main/java/org/xwiki/
> Â contrib/sandbox/xwiki-wiki-components/src/main/java/org/xwiki/component/
> Â contrib/sandbox/xwiki-wiki-components/src/main/java/org/xwiki/component/wiki/
> Â contrib/sandbox/xwiki-wiki-components/src/main/java/org/xwiki/component/wiki/InvalidComponentDefinitionException.java
> Â contrib/sandbox/xwiki-wiki-components/src/main/java/org/xwiki/component/wiki/MethodOutputHandler.java
> Â contrib/sandbox/xwiki-wiki-components/src/main/java/org/xwiki/component/wiki/WikiComponent.java
> Â contrib/sandbox/xwiki-wiki-components/src/main/java/org/xwiki/component/wiki/WikiComponentBuilder.java
> Â contrib/sandbox/xwiki-wiki-components/src/main/java/org/xwiki/component/wiki/WikiComponentException.java
> Â contrib/sandbox/xwiki-wiki-components/src/main/java/org/xwiki/component/wiki/WikiComponentInvocationHandler.java
> Â contrib/sandbox/xwiki-wiki-components/src/main/java/org/xwiki/component/wiki/WikiComponentManager.java
> Â contrib/sandbox/xwiki-wiki-components/src/main/java/org/xwiki/component/wiki/internal/
> Â contrib/sandbox/xwiki-wiki-components/src/main/java/org/xwiki/component/wiki/internal/DefaultMethodOutputHandler.java
> Â contrib/sandbox/xwiki-wiki-components/src/main/java/org/xwiki/component/wiki/internal/DefaultWikiComponent.java
> Â contrib/sandbox/xwiki-wiki-components/src/main/java/org/xwiki/component/wiki/internal/DefaultWikiComponentManager.java
> Â contrib/sandbox/xwiki-wiki-components/src/main/resources/
> Â contrib/sandbox/xwiki-wiki-components/src/main/resources/META-INF/
> Â contrib/sandbox/xwiki-wiki-components/src/main/resources/META-INF/components.txt
> Â contrib/sandbox/xwiki-wiki-components/src/test/
> Â contrib/sandbox/xwiki-wiki-components/src/test/java/
> Â contrib/sandbox/xwiki-wiki-components/src/test/java/org/
> Â contrib/sandbox/xwiki-wiki-components/src/test/java/org/xwiki/
> Â contrib/sandbox/xwiki-wiki-components/src/test/java/org/xwiki/component/
> Â contrib/sandbox/xwiki-wiki-components/src/test/java/org/xwiki/component/wiki/
> Â contrib/sandbox/xwiki-wiki-components/src/test/java/org/xwiki/component/wiki/WikiComponentManagerTest.java
> Log:
> XWIKI-5195 Make possible to implement any component from the wiki, using objects
>
> Proposal implementation, for review. Right now supports definition of component implementation as wiki objects, with support for multiple interfaces implementations and methods return value via explicit call or plain block rendering if no explicit call and return type is String.
>
> Missing :
> - More tests
> - Support for requirements bindings
> - Support for inputs handling (method arguments bindings)
>
> Open questions I can think of :
> - Should we refuse to register a component if it does not declare implementation of all its role methods ? (to avoid potential NPEs, for example)
Why NPE ? The proxy is supposed to generate a proper exception when
something is calling unimplemented method.
> - Better name for XWiki.ComponentInterfaceClass ? (It's the class representing an extra interface the component implementation implements)=
>
> Note: module right now relies on XWIKI-5194 (bridge event for XWiki initialized) being applied to xwiki-core/xwiki-bridge
>
>
[...]
>
> Added: contrib/sandbox/xwiki-wiki-components/src/main/java/com/xpn/xwiki/internal/DefaultWikiComponentBuilder.java
> ===================================================================
> --- contrib/sandbox/xwiki-wiki-components/src/main/java/com/xpn/xwiki/internal/DefaultWikiComponentBuilder.java             (rev 0)
> +++ contrib/sandbox/xwiki-wiki-components/src/main/java/com/xpn/xwiki/internal/DefaultWikiComponentBuilder.java 2010-05-15 15:08:25 UTC (rev 28878)
> @@ -0,0 +1,167 @@
[...]
> +/**
> + * Default implementation of a wiki component builder, that is using the legacy XWiki core module.
> + *
> + * @since 2.4-M2
> + * @version $Id$
> + */
> +@Component
> +public class DefaultWikiComponentBuilder implements WikiComponentBuilder
> +{
> +
> + Â Â /**
> + Â Â * The name of the document that holds the XClass definition of an implementation of an interface by a component.
> + Â Â */
> + Â Â private static final String XWIKI_COMPONENT_INTERFACE_CLASS = "XWiki.ComponentInterfaceClass";
> +
> + Â Â /**
> + Â Â * The name of the document that holds the XClass definition of a method of a component.
> + Â Â */
> + Â Â private static final String XWIKI_COMPONENT_METHOD_CLASS = "XWiki.ComponentMethodClass";
> +
> + Â Â /**
> + Â Â * The property name of the name of a component method.
> + Â Â */
> + Â Â private static final String COMPONENT_METHOD_NAME_FIELD = "name";
> +
> + Â Â /**
> + Â Â * The property name of the name of an implemented interface. (Checkstyle fix).
> + Â Â */
> + Â Â private static final String COMPONENT_INTERFACE_NAME_FIELD = COMPONENT_METHOD_NAME_FIELD;
> +
> + Â Â /**
> + Â Â * Execution, needed to access the XWiki context map.
> + Â Â */
> + Â Â @Requirement
> + Â Â private Execution execution;
> +
> + Â Â /**
> + Â Â * {@inheritDoc}
> + Â Â */
> + Â Â public WikiComponent build(DocumentReference reference) throws InvalidComponentDefinitionException,
> + Â Â Â Â WikiComponentException
> + Â Â {
> + Â Â Â Â try {
> + Â Â Â Â Â Â XWikiDocument componentDocument = getXWikiContext().getWiki().getDocument(reference, getXWikiContext());
> + Â Â Â Â Â Â BaseObject componentObject = componentDocument.getObject("XWiki.ComponentClass");
> +
> + Â Â Â Â Â Â if (componentObject == null) {
> + Â Â Â Â Â Â Â Â throw new InvalidComponentDefinitionException("No component object could be found");
> + Â Â Â Â Â Â }
> +
> + Â Â Â Â Â Â String role = componentObject.getStringValue("role");
> +
> + Â Â Â Â Â Â if (StringUtils.isBlank(role)) {
> + Â Â Â Â Â Â Â Â throw new InvalidComponentDefinitionException("No role were precised in the component");
> + Â Â Â Â Â Â }
> +
> + Â Â Â Â Â Â Class< ? > roleAsClass;
> + Â Â Â Â Â Â try {
> + Â Â Â Â Â Â Â Â roleAsClass = Class.forName(role);
> + Â Â Â Â Â Â } catch (ClassNotFoundException e) {
> + Â Â Â Â Â Â Â Â throw new InvalidComponentDefinitionException("The role class could not be found", e);
> + Â Â Â Â Â Â }
> +
> + Â Â Â Â Â Â String roleHint = StringUtils.defaultIfEmpty(componentObject.getStringValue("roleHint"), "default");
> +
> + Â Â Â Â Â Â DefaultWikiComponent component = new DefaultWikiComponent(reference, roleAsClass, roleHint);
> + Â Â Â Â Â Â component.setHandledMethods(this.getHandledMethods(componentDocument));
> + Â Â Â Â Â Â component.setImplementedInterfaces(this.getDeclaredInterfaces(componentDocument));
> +
> + Â Â Â Â Â Â return component;
> +
> + Â Â Â Â } catch (XWikiException e) {
> + Â Â Â Â Â Â throw new WikiComponentException("Failed to build wiki component for document " + reference.toString());
> + Â Â Â Â }
> + Â Â }
> +
> + Â Â /**
> + Â Â * @param componentDocument the document holding the component description
> + Â Â * @return the map of component handled methods/method body
> + Â Â */
> + Â Â private Map<String, String> getHandledMethods(XWikiDocument componentDocument)
> + Â Â {
> + Â Â Â Â Map<String, String> handledMethods = new HashMap<String, String>();
> + Â Â Â Â if (componentDocument.getObjectNumbers(XWIKI_COMPONENT_METHOD_CLASS) > 0) {
> + Â Â Â Â Â Â for (BaseObject iface : componentDocument.getObjects(XWIKI_COMPONENT_METHOD_CLASS)) {
> + Â Â Â Â Â Â Â Â if (!StringUtils.isBlank(iface.getStringValue(COMPONENT_METHOD_NAME_FIELD))) {
> + Â Â Â Â Â Â Â Â Â Â handledMethods.put(iface.getStringValue(COMPONENT_METHOD_NAME_FIELD), iface.getStringValue("code"));
> + Â Â Â Â Â Â Â Â }
> + Â Â Â Â Â Â }
> + Â Â Â Â }
> + Â Â Â Â return handledMethods;
> +
> + Â Â }
> +
> + Â Â /**
> + Â Â * @param componentDocument the document holding the component description
> + Â Â * @return the array of interfaces declared (and actually existing) by the document
> + Â Â */
> + Â Â private Class< ? >[] getDeclaredInterfaces(XWikiDocument componentDocument)
> + Â Â {
> + Â Â Â Â List<Class< ? >> interfaces = new ArrayList<Class< ? >>();
> + Â Â Â Â if (componentDocument.getObjectNumbers(XWIKI_COMPONENT_INTERFACE_CLASS) > 0) {
> + Â Â Â Â Â Â for (BaseObject iface : componentDocument.getObjects(XWIKI_COMPONENT_INTERFACE_CLASS)) {
> + Â Â Â Â Â Â Â Â if (!StringUtils.isBlank(iface.getStringValue(COMPONENT_INTERFACE_NAME_FIELD))) {
> + Â Â Â Â Â Â Â Â Â Â try {
> + Â Â Â Â Â Â Â Â Â Â Â Â Class< ? > implemented = Class.forName(iface.getStringValue(COMPONENT_INTERFACE_NAME_FIELD));
> + Â Â Â Â Â Â Â Â Â Â Â Â interfaces.add(implemented);
> + Â Â Â Â Â Â Â Â Â Â } catch (ClassNotFoundException e) {
> + Â Â Â Â Â Â Â Â Â Â Â Â // Silent
> + Â Â Â Â Â Â Â Â Â Â }
> + Â Â Â Â Â Â Â Â }
> + Â Â Â Â Â Â }
> + Â Â Â Â }
> + Â Â Â Â return interfaces.toArray(new Class< ? >[] {});
> + Â Â }
> +
> + Â Â /**
> + Â Â * @return a XWikiContext, retrieved from our execution
> + Â Â */
> + Â Â private XWikiContext getXWikiContext()
> + Â Â {
> + Â Â Â Â return (XWikiContext) execution.getContext().getProperty("xwikicontext");
> + Â Â }
> +
> +}
>
> Added: contrib/sandbox/xwiki-wiki-components/src/main/java/com/xpn/xwiki/internal/WikiComponentInitializer.java
> ===================================================================
> --- contrib/sandbox/xwiki-wiki-components/src/main/java/com/xpn/xwiki/internal/WikiComponentInitializer.java               (rev 0)
> +++ contrib/sandbox/xwiki-wiki-components/src/main/java/com/xpn/xwiki/internal/WikiComponentInitializer.java   2010-05-15 15:08:25 UTC (rev 28878)
> @@ -0,0 +1,339 @@
[...]
> +/**
> + * Initializes the Wiki Component feature. First ensure all needed XClasses are up-to-date, then registers existing
> + * components.
> + *
> + * @since 2.4-M2
> + * @version $Id$
> + */
> +@Component("wikiComponentInitializer")
> +public class WikiComponentInitializer extends AbstractLogEnabled implements EventListener
> +{
> + Â Â /**
> + Â Â * The XClass defining a component implementation.
> + Â Â */
> + Â Â private static final String WIKI_COMPONENT_CLASS = "XWiki.ComponentClass";
> +
> + Â Â /**
> + Â Â * The XClass defining a component requirement.
> + Â Â */
> + Â Â private static final String WIKI_COMPONENT_REQUIREMENT_CLASS = "XWiki.ComponentRequirementClass";
> +
> + Â Â /**
> + Â Â * The XClass defining a component method.
> + Â Â */
> + Â Â private static final String WIKI_COMPONENT_METHOD_CLASS = "XWiki.ComponentMethodClass";
> +
> + Â Â /**
> + Â Â * The XClass defining a component interface implementation.
> + Â Â */
> + Â Â private static final String WIKI_COMPONENT_INTERFACE_CLASS = "XWiki.ComponentInterfaceClass";
> +
> + Â Â /**
> + Â Â * The name property of the {@link WIKI_COMPONENT_INTERFACE_CLASS} XClass.
> + Â Â */
> + Â Â private static final String INTERFACE_NAME_FIELD = "name";
> +
> + Â Â /**
> + Â Â * The name property of the {@link WIKI_COMPONENT_METHOD_CLASS} XClass. (Fix checkstyle).
> + Â Â */
> + Â Â private static final String METHOD_NAME_FIELD = INTERFACE_NAME_FIELD;
> +
> + Â Â /**
> + Â Â * The role property of both {@link WIKI_COMPONENT_CLASS} and {@link WIKI_COMPONENT_REQUIREMENT_CLASS}.
> + Â Â */
> + Â Â private static final String COMPONENT_ROLE_HINT_FIELD = "roleHint";
> +
> + Â Â /**
> + Â Â * The role hint property of both {@link WIKI_COMPONENT_CLASS} and {@link WIKI_COMPONENT_REQUIREMENT_CLASS}.
> + Â Â */
> + Â Â private static final String COMPONENT_ROLE_FIELD = "role";
> +
> + Â Â /**
> + Â Â * Our execution. Needed to access the XWiki context.
> + Â Â */
> + Â Â @Requirement
> + Â Â private Execution execution;
> +
> + Â Â /**
> + Â Â * The wiki component manager that knows how to register component definition against the underlying CM.
> + Â Â */
> + Â Â @Requirement
> + Â Â private WikiComponentManager wikiComponentManager;
> +
> + Â Â /**
> + Â Â * Builder that creates component description from document references.
> + Â Â */
> + Â Â @Requirement
> + Â Â private WikiComponentBuilder wikiComponentBuilder;
> +
> + Â Â /**
> + Â Â * {@inheritDoc}
> + Â Â */
> + Â Â public List<Event> getEvents()
> + Â Â {
> + Â Â Â Â return Arrays.<Event> asList(new XWikiInitializedBridgeEvent());
> + Â Â }
> +
> + Â Â /**
> + Â Â * {@inheritDoc}
> + Â Â */
> + Â Â public String getName()
> + Â Â {
> + Â Â Â Â return "wikiComponentInitializer";
> + Â Â }
> +
> + Â Â /**
> + Â Â * {@inheritDoc}
> + Â Â */
> + Â Â public void onEvent(Event arg0, Object arg1, Object arg2)
> + Â Â {
> + Â Â Â Â // First step, verify that all XClasses exists and are up-to-date (act if not).
> + Â Â Â Â this.installOrUpdateComponentXClasses();
> + Â Â Â Â // Second step, lookup and register existing components.
> + Â Â Â Â this.registerExistingWikiComponents();
> + Â Â }
> +
> + Â Â /**
> + Â Â * Registers existing components. Query them against the store, and if they are built properly (valid definition)
> + Â Â * register them against the CM.
> + Â Â */
> + Â Â private void registerExistingWikiComponents()
> + Â Â {
> + Â Â Â Â String query =
> + Â Â Â Â Â Â ", BaseObject as obj, StringProperty as role where obj.className='XWiki.ComponentClass'"
> + Â Â Â Â Â Â Â Â + " and obj.name=doc.fullName and role.id.id=obj.id and role.id.name='role' and role.value <>''";
> + Â Â Â Â try {
> + Â Â Â Â Â Â for (DocumentReference ref : getXWikiContext().getWiki().getStore().searchDocumentReferences(query,
> + Â Â Â Â Â Â Â Â getXWikiContext())) {
> + Â Â Â Â Â Â Â Â try {
> + Â Â Â Â Â Â Â Â Â Â WikiComponent component = this.wikiComponentBuilder.build(ref);
> +
> + Â Â Â Â Â Â Â Â Â Â this.wikiComponentManager.registerWikiComponent(component);
> + Â Â Â Â Â Â Â Â } catch (InvalidComponentDefinitionException e) {
> + Â Â Â Â Â Â Â Â Â Â // Fail quietly and only log at the debug level.
> + Â Â Â Â Â Â Â Â Â Â getLogger().debug("Invalid wiki component definition for reference " + ref.toString(), e);
> + Â Â Â Â Â Â Â Â } catch (WikiComponentException e) {
> + Â Â Â Â Â Â Â Â Â Â // Fail quietly and only log at the debug level.
> + Â Â Â Â Â Â Â Â Â Â getLogger().debug("Failed to register wiki component for reference " + ref.toString(), e);
> + Â Â Â Â Â Â Â Â }
> + Â Â Â Â Â Â }
> + Â Â Â Â } catch (XWikiException e) {
> + Â Â Â Â Â Â getLogger().error("Failed to register existing wiki components", e);
> + Â Â Â Â }
> +
> + Â Â }
> +
> + Â Â /**
> + Â Â * Verify that all XClasses exists and are up-to-date (act if not).
> + Â Â */
> + Â Â private void installOrUpdateComponentXClasses()
> + Â Â {
> + Â Â Â Â try {
> + Â Â Â Â Â Â this.installOrUpdateComponentXClass();
> + Â Â Â Â Â Â this.installOrUpdateComponentRequirementXClass();
> + Â Â Â Â Â Â this.installOrUpdateComponentMethodXClass();
> + Â Â Â Â Â Â this.installOrUpdateComponentInterfaceXClass();
> + Â Â Â Â } catch (XWikiException e) {
> + Â Â Â Â Â Â getLogger().error("Failed to install or update wiki component XClasses", e);
> + Â Â Â Â }
> + Â Â }
> +
> + Â Â /**
> + Â Â * Verify that the {@link #WIKI_COMPONENT_INTERFACE_CLASS} exists and is up-to-date (act if not).
> + Â Â *
> + Â Â * @throws XWikiException on failure
> + Â Â */
> + Â Â private void installOrUpdateComponentInterfaceXClass() throws XWikiException
> + Â Â {
> + Â Â Â Â XWikiContext xcontext = getXWikiContext();
> + Â Â Â Â XWikiDocument doc = xcontext.getWiki().getDocument(WIKI_COMPONENT_INTERFACE_CLASS, xcontext);
> +
> + Â Â Â Â BaseClass bclass = doc.getXClass();
> + Â Â Â Â bclass.setName(WIKI_COMPONENT_INTERFACE_CLASS);
> +
> + Â Â Â Â boolean needsUpdate = false;
> +
> + Â Â Â Â needsUpdate |= this.initializeXClassDocumentMetadata(doc, "Wiki Component Implements Interface XWiki Class");
> + Â Â Â Â needsUpdate |= bclass.addTextField(INTERFACE_NAME_FIELD, "Interface Qualified Name", 30);
> +
> + Â Â Â Â if (needsUpdate) {
> + Â Â Â Â Â Â this.update(doc);
> + Â Â Â Â }
> + Â Â }
> +
> + Â Â /**
> + Â Â * Verify that the {@link #WIKI_COMPONENT_CLASS} exists and is up-to-date (act if not).
> + Â Â *
> + Â Â * @throws XWikiException on failure
> + Â Â */
> + Â Â private void installOrUpdateComponentXClass() throws XWikiException
> + Â Â {
> + Â Â Â Â XWikiContext xcontext = getXWikiContext();
> + Â Â Â Â XWikiDocument doc = xcontext.getWiki().getDocument(WIKI_COMPONENT_CLASS, xcontext);
> +
> + Â Â Â Â BaseClass bclass = doc.getXClass();
> + Â Â Â Â bclass.setName(WIKI_COMPONENT_CLASS);
> +
> + Â Â Â Â boolean needsUpdate = false;
> +
> + Â Â Â Â needsUpdate |= this.initializeXClassDocumentMetadata(doc, "Wiki Component XWiki Class");
> + Â Â Â Â needsUpdate |= bclass.addTextField(COMPONENT_ROLE_FIELD, "Component role", 30);
> + Â Â Â Â needsUpdate |= bclass.addTextField(COMPONENT_ROLE_HINT_FIELD, "Component role hint", 30);
> +
> + Â Â Â Â if (needsUpdate) {
> + Â Â Â Â Â Â this.update(doc);
> + Â Â Â Â }
> + Â Â }
> +
> + Â Â /**
> + Â Â * Verify that the {@link #WIKI_COMPONENT_REQUIREMENT_CLASS} exists and is up-to-date (act if not).
> + Â Â *
> + Â Â * @throws XWikiException on failure
> + Â Â */
> + Â Â private void installOrUpdateComponentRequirementXClass() throws XWikiException
> + Â Â {
> + Â Â Â Â XWikiContext xcontext = getXWikiContext();
> + Â Â Â Â XWikiDocument doc = xcontext.getWiki().getDocument(WIKI_COMPONENT_REQUIREMENT_CLASS, xcontext);
> +
> + Â Â Â Â BaseClass bclass = doc.getXClass();
> + Â Â Â Â bclass.setName(WIKI_COMPONENT_REQUIREMENT_CLASS);
> +
> + Â Â Â Â boolean needsUpdate = false;
> +
> + Â Â Â Â needsUpdate |= this.initializeXClassDocumentMetadata(doc, "Wiki Component Requirement XWiki Class");
> + Â Â Â Â needsUpdate |= bclass.addTextField(COMPONENT_ROLE_FIELD, "Requirement role", 30);
> + Â Â Â Â needsUpdate |= bclass.addTextField(COMPONENT_ROLE_HINT_FIELD, "Requirement role hint", 30);
> + Â Â Â Â needsUpdate |= bclass.addTextField("bindingName", "Binding name", 30);
> + Â Â Â Â needsUpdate |= bclass.addStaticListField("type", "Requirement type", "single=Single|list=List|map=Map");
> +
> + Â Â Â Â if (needsUpdate) {
> + Â Â Â Â Â Â this.update(doc);
> + Â Â Â Â }
> + Â Â }
> +
> + Â Â /**
> + Â Â * Verify that the {@link #WIKI_COMPONENT_METHOD_CLASS} exists and is up-to-date (act if not).
> + Â Â *
> + Â Â * @throws XWikiException on failure
> + Â Â */
> + Â Â private void installOrUpdateComponentMethodXClass() throws XWikiException
> + Â Â {
> + Â Â Â Â XWikiContext xcontext = getXWikiContext();
> + Â Â Â Â XWikiDocument doc = xcontext.getWiki().getDocument(WIKI_COMPONENT_METHOD_CLASS, xcontext);
> +
> + Â Â Â Â BaseClass bclass = doc.getXClass();
> + Â Â Â Â bclass.setName(WIKI_COMPONENT_METHOD_CLASS);
> +
> + Â Â Â Â boolean needsUpdate = false;
> +
> + Â Â Â Â needsUpdate |= this.initializeXClassDocumentMetadata(doc, "Wiki Component Method XWiki Class");
> + Â Â Â Â needsUpdate |= bclass.addTextField(METHOD_NAME_FIELD, "Method name", 30);
> + Â Â Â Â needsUpdate |= bclass.addTextAreaField("code", "Method body code", 40, 20);
> +
> + Â Â Â Â if (needsUpdate) {
> + Â Â Â Â Â Â this.update(doc);
> + Â Â Â Â }
> + Â Â }
> +
> + Â Â /**
> + Â Â * Utility method for updating a wiki macro class definition document.
> + Â Â *
> + Â Â * @param doc xwiki document containing the wiki macro class.
> + Â Â * @throws XWikiException if an error occurs while saving the document.
> + Â Â */
> + Â Â private void update(XWikiDocument doc) throws XWikiException
> + Â Â {
> + Â Â Â Â XWikiContext xcontext = getXWikiContext();
> + Â Â Â Â xcontext.getWiki().saveDocument(doc, xcontext);
> + Â Â }
> +
> + Â Â /**
> + Â Â * Helper method to prepare a document that will hold an XClass definition, setting its initial metadata, if needed
> + Â Â * (author, title, parent, content, etc.).
> + Â Â *
> + Â Â * @param doc the document to prepare
> + Â Â * @param title the title to set
> + Â Â * @return true if the doc has been modified and needs saving, false otherwise
> + Â Â */
> + Â Â private boolean initializeXClassDocumentMetadata(XWikiDocument doc, String title)
> + Â Â {
> + Â Â Â Â boolean needsUpdate = false;
> +
> + Â Â Â Â if (StringUtils.isBlank(doc.getCreator())) {
> + Â Â Â Â Â Â needsUpdate = true;
> + Â Â Â Â Â Â doc.setCreator(XWikiRightService.SUPERADMIN_USER);
> + Â Â Â Â }
> + Â Â Â Â if (StringUtils.isBlank(doc.getAuthor())) {
> + Â Â Â Â Â Â needsUpdate = true;
> + Â Â Â Â Â Â doc.setAuthor(doc.getCreator());
> + Â Â Â Â }
> + Â Â Â Â if (StringUtils.isBlank(doc.getParent())) {
> + Â Â Â Â Â Â needsUpdate = true;
> + Â Â Â Â Â Â doc.setParent("XWiki.XWikiClasses");
> + Â Â Â Â }
> + Â Â Â Â if (StringUtils.isBlank(doc.getTitle())) {
> + Â Â Â Â Â Â needsUpdate = true;
> + Â Â Â Â Â Â doc.setTitle(title);
> + Â Â Â Â }
> + Â Â Â Â if (StringUtils.isBlank(doc.getContent()) || !XWikiDocument.XWIKI20_SYNTAXID.equals(doc.getSyntaxId())) {
> + Â Â Â Â Â Â needsUpdate = true;
> + Â Â Â Â Â Â doc.setContent("{{include document=\"XWiki.ClassSheet\" /}}");
> + Â Â Â Â Â Â doc.setSyntaxId(XWikiDocument.XWIKI20_SYNTAXID);
> + Â Â Â Â }
> + Â Â Â Â return needsUpdate;
> + Â Â }
> +
> + Â Â /**
> + Â Â * @return the XWikiContext extracted from the execution.
> + Â Â */
> + Â Â private XWikiContext getXWikiContext()
> + Â Â {
> + Â Â Â Â return (XWikiContext) this.execution.getContext().getProperty("xwikicontext");
> + Â Â }
> +
> +}
>
> Added: contrib/sandbox/xwiki-wiki-components/src/main/java/org/xwiki/component/wiki/InvalidComponentDefinitionException.java
> ===================================================================
> --- contrib/sandbox/xwiki-wiki-components/src/main/java/org/xwiki/component/wiki/InvalidComponentDefinitionException.java                (rev 0)
> +++ contrib/sandbox/xwiki-wiki-components/src/main/java/org/xwiki/component/wiki/InvalidComponentDefinitionException.java    2010-05-15 15:08:25 UTC (rev 28878)
> @@ -0,0 +1,59 @@
[...]
> +/**
> + * Exception thrown by component builders when a document holds an invalid compoentn definition.
> + * (For example if no role has been specified).
> + *
> + * Â @since 2.4-M2
> + * Â @version $Id$
> + */
> +public class InvalidComponentDefinitionException extends Exception
> +{
> + Â Â /**
> + Â Â * Constructor of this exception.
> + Â Â */
> + Â Â public InvalidComponentDefinitionException()
> + Â Â {
> + Â Â Â Â super();
> + Â Â }
> +
> + Â Â /**
> + Â Â * Constructor of this exception.
> + Â Â *
> + Â Â * @param message a message associated with the exception, that explains why the definition is invalid
> + Â Â */
> + Â Â public InvalidComponentDefinitionException(String message)
> + Â Â {
> + Â Â Â Â super(message);
> + Â Â }
> +
> + Â Â /**
> + Â Â * Constructor of this exception.
> + Â Â *
> + Â Â * @param message a message associated with the exception, that explains why the definition is invalid
> + Â Â * @param t the root cause
> + Â Â */
> + Â Â public InvalidComponentDefinitionException(String message, Throwable t)
> + Â Â {
> + Â Â Â Â super(message);
> + Â Â }
> +}
>
> Added: contrib/sandbox/xwiki-wiki-components/src/main/java/org/xwiki/component/wiki/MethodOutputHandler.java
> ===================================================================
> --- contrib/sandbox/xwiki-wiki-components/src/main/java/org/xwiki/component/wiki/MethodOutputHandler.java                (rev 0)
> +++ contrib/sandbox/xwiki-wiki-components/src/main/java/org/xwiki/component/wiki/MethodOutputHandler.java    2010-05-15 15:08:25 UTC (rev 28878)
> @@ -0,0 +1,44 @@
[...]
> +/**
> + * Utility for wiki methods to return a value. An implementation of this interface is binded in the context of a
> + * wiki method execution, so that such method scripts can return a value using {@link #returnValue(Object)}.
> + *
> + * @since 2.4-M2
> + * @version $Id$
> + */
> +public interface MethodOutputHandler
> +{
> +
> + Â Â /**
> + Â Â * Stores a value in the method invocation context for further return.
> + Â Â * Note that if this method is called multiple times during the invocation, the last one wins.
> + Â Â *
> + Â Â * @param value the value to return
> + Â Â */
> + Â Â void returnValue(Object value);
> +
> + Â Â /**
> + Â Â * @return the current stored return value (null if not set yet).
> + Â Â */
> + Â Â Object getReturnValue();
> +}
>
> Added: contrib/sandbox/xwiki-wiki-components/src/main/java/org/xwiki/component/wiki/WikiComponent.java
> ===================================================================
> --- contrib/sandbox/xwiki-wiki-components/src/main/java/org/xwiki/component/wiki/WikiComponent.java               (rev 0)
> +++ contrib/sandbox/xwiki-wiki-components/src/main/java/org/xwiki/component/wiki/WikiComponent.java   2010-05-15 15:08:25 UTC (rev 28878)
> @@ -0,0 +1,58 @@
[...]
> +/**
> + * Represents the definition of a wiki component implementation.
> + *
> + * @since 2.4-M2
> + * @version $Id$
> + */
> +public interface WikiComponent
> +{
> + Â Â /**
> + Â Â * @return the reference to the document holding this wiki component definition.
> + Â Â */
> + Â Â DocumentReference getDocumentReference();
> +
> + Â Â /**
> + Â Â * @return the role implemented by this component implementation.
> + Â Â */
> + Â Â Class< ? > getRole();
> +
> + Â Â /**
> + Â Â * @return the hint of the role implemented by this component implementation.
> + Â Â */
> + Â Â String getRoleHint();
> +
> + Â Â /**
> + Â Â * @return the extra list of interfaces this component implementation implements.
> + Â Â */
> + Â Â Class< ? >[] getImplementedInterfaces();
> +
> + Â Â /**
> + Â Â * @return the map of method name/wiki code this component implementation handles.
> + Â Â */
> + Â Â Map<String, String> getHandledMethods();
> +}
>
> Added: contrib/sandbox/xwiki-wiki-components/src/main/java/org/xwiki/component/wiki/WikiComponentBuilder.java
> ===================================================================
> --- contrib/sandbox/xwiki-wiki-components/src/main/java/org/xwiki/component/wiki/WikiComponentBuilder.java                (rev 0)
> +++ contrib/sandbox/xwiki-wiki-components/src/main/java/org/xwiki/component/wiki/WikiComponentBuilder.java    2010-05-15 15:08:25 UTC (rev 28878)
> @@ -0,0 +1,46 @@
[...]
> +/**
> + * Constructs a {@link WikiComponent} out of the data contained in the document pointed by a {@link DocumentReference}.
> + *
> + * @since 2.4-M2
> + * @version $Id$
> + */
> +@ComponentRole
> +public interface WikiComponentBuilder
> +{
> +
> + Â Â /**
> + Â Â * Builds a wiki component representation extracting the data stored as objects of document.
> + Â Â *
> + Â Â * @param reference the reference to the document that holds component definition objects
> + Â Â * @return the constructed component definition
> + Â Â * @throws InvalidComponentDefinitionException when the data in the document is not a valid component definition
> + Â Â * @throws WikiComponentException the builder failed to create the component out of the document (for example due to
> + Â Â * Â Â Â Â Â Â a failure by tge underlying store, etc.)
> + Â Â */
> + Â Â WikiComponent build(DocumentReference reference) throws InvalidComponentDefinitionException, WikiComponentException;
> +
> +}
>
> Added: contrib/sandbox/xwiki-wiki-components/src/main/java/org/xwiki/component/wiki/WikiComponentException.java
> ===================================================================
> --- contrib/sandbox/xwiki-wiki-components/src/main/java/org/xwiki/component/wiki/WikiComponentException.java               (rev 0)
> +++ contrib/sandbox/xwiki-wiki-components/src/main/java/org/xwiki/component/wiki/WikiComponentException.java   2010-05-15 15:08:25 UTC (rev 28878)
> @@ -0,0 +1,51 @@
[...]
> +/**
> + * A generic exception thrown by this module, usually a wrapper around lower level exceptions.
> + *
> + * @since 2.4-M2
> + * @version $Id$
> + */
> +public class WikiComponentException extends Exception
> +{
> + Â Â /**
> + Â Â * Constructor of this exception.
> + Â Â *
> + Â Â * @param message the message associated with the exception
> + Â Â */
> + Â Â public WikiComponentException(String message)
> + Â Â {
> + Â Â Â Â super(message);
> + Â Â }
> +
> + Â Â /**
> + Â Â * Constructor of this exception.
> + Â Â *
> + Â Â * @param message the message associated with the exception
> + Â Â * @param t the root cause
> + Â Â */
> + Â Â public WikiComponentException(String message, Throwable t)
> + Â Â {
> + Â Â Â Â super(message, t);
> + Â Â }
> +
> +}
>
> Added: contrib/sandbox/xwiki-wiki-components/src/main/java/org/xwiki/component/wiki/WikiComponentInvocationHandler.java
> ===================================================================
> --- contrib/sandbox/xwiki-wiki-components/src/main/java/org/xwiki/component/wiki/WikiComponentInvocationHandler.java               (rev 0)
> +++ contrib/sandbox/xwiki-wiki-components/src/main/java/org/xwiki/component/wiki/WikiComponentInvocationHandler.java   2010-05-15 15:08:25 UTC (rev 28878)
> @@ -0,0 +1,245 @@
[...]
> +/**
> + * Method invocation handler for wiki component proxy instances. Has a reference on a map of name/body wiki code of
> + * supported methods.
> + *
> + * @since 2.4-M2
> + * @version $Id$
> + */
> +public class WikiComponentInvocationHandler implements InvocationHandler
> +{
> + Â Â /**
> + Â Â * The key under which the output is kept in the method invocation context.
> + Â Â */
> + Â Â private static final String METHOD_CONTEXT_OUTPUT_KEY = "output";
> +
> + Â Â /**
> + Â Â * The key under which the context document is kept in the XWiki context.
> + Â Â */
> + Â Â private static final String XWIKI_CONTEXT_DOC_KEY = "doc";
> +
> + Â Â /**
> + Â Â * Pre-loaded hasCode Method.
> + Â Â *
> + Â Â * @see {@link Object#hashCode()}
> + Â Â */
> + Â Â private static Method hashCodeMethod;
> +
> + Â Â /**
> + Â Â * Pre-loaded equals method.
> + Â Â *
> + Â Â * @see {@link Object#equals(Object)}
> + Â Â */
> + Â Â private static Method equalsMethod;
> +
> + Â Â /**
> + Â Â * Pre-loaded toString method.
> + Â Â *
> + Â Â * @see {@link Object#toString()}
> + Â Â */
> + Â Â private static Method toStringMethod;
> +
> + Â Â static {
> + Â Â Â Â try {
> + Â Â Â Â Â Â hashCodeMethod = Object.class.getMethod("hashCode", null);
> + Â Â Â Â Â Â equalsMethod = Object.class.getMethod("equals", new Class[] {Object.class});
> + Â Â Â Â Â Â toStringMethod = Object.class.getMethod("toString", null);
> + Â Â Â Â } catch (NoSuchMethodException e) {
> + Â Â Â Â Â Â throw new NoSuchMethodError(e.getMessage());
> + Â Â Â Â }
> + Â Â }
> +
> + Â Â /**
> + Â Â * Map hosting handled methods. Keys are method names and values are wiki code to "execute".
> + Â Â */
> + Â Â private Map<String, String> handledMethods;
> +
> + Â Â /**
> + Â Â * Our component manager.
> + Â Â */
> + Â Â private ComponentManager componentManager;
> +
> + Â Â /**
> + Â Â * The reference to the document.
> + Â Â */
> + Â Â private DocumentReference componentReference;
> +
> + Â Â /**
> + Â Â * Constructor of this invocation handler.
> + Â Â *
> + Â Â * @param componentReference reference to the document holding the component definition
> + Â Â * @param methods the map of methods handled by the component instance
> + Â Â * @param componentManager the component manager
> + Â Â */
> + Â Â public WikiComponentInvocationHandler(DocumentReference componentReference, Map<String, String> methods,
> + Â Â Â Â ComponentManager componentManager)
> + Â Â {
> + Â Â Â Â this.componentReference = componentReference;
> + Â Â Â Â this.handledMethods = methods;
> + Â Â Â Â this.componentManager = componentManager;
> + Â Â }
> +
> + Â Â /**
> + Â Â * {@inheritDoc}
> + Â Â */
> + Â Â public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
> + Â Â {
> + Â Â Â Â if (!this.handledMethods.containsKey(method.getName())) {
> + Â Â Â Â Â Â if (method.getDeclaringClass() == Object.class) {
> + Â Â Â Â Â Â Â Â return this.proxyObjectMethod(proxy, method, args);
> + Â Â Â Â Â Â } else {
> + Â Â Â Â Â Â Â Â throw new NoSuchMethodException();
> + Â Â Â Â Â Â }
> + Â Â Â Â } else {
> + Â Â Â Â Â Â return this.executeWikiContent(method);
> + Â Â Â Â }
> +
> + Â Â }
> +
> + Â Â /**
> + Â Â * "Executes" the wiki content associated to the passed method.
> + Â Â *
> + Â Â * @param method the method to execute
> + Â Â * @return the result of the execution
> + Â Â * @throws Exception when an error occurs during execution
> + Â Â */
> + Â Â @SuppressWarnings("unchecked")
> + Â Â private Object executeWikiContent(Method method) throws Exception
> + Â Â {
> + Â Â Â Â XDOM xdom;
> + Â Â Â Â Map xwikiContext = null;
> + Â Â Â Â Object contextDoc = null;
> +
> + Â Â Â Â Parser parser = componentManager.lookup(Parser.class, Syntax.XWIKI_2_0.toIdString());
> + Â Â Â Â xdom = parser.parse(new StringReader(this.handledMethods.get(method.getName())));
> +
> + Â Â Â Â Execution execution = componentManager.lookup(Execution.class);
> + Â Â Â Â Transformation macroTransformation = componentManager.lookup(Transformation.class, "macro");
> + Â Â Â Â DocumentAccessBridge docBridge = componentManager.lookup(DocumentAccessBridge.class);
> +
> + Â Â Â Â Map<String, Object> methodContext = new HashMap<String, Object>();
> + Â Â Â Â methodContext.put(METHOD_CONTEXT_OUTPUT_KEY, new DefaultMethodOutputHandler());
> +
> + Â Â Â Â // Place macro context inside xwiki context ($context.macro).
> + Â Â Â Â xwikiContext = (Map) execution.getContext().getProperty("xwikicontext");
> + Â Â Â Â xwikiContext.put("method", methodContext);
> + Â Â Â Â // Save current context document.
> + Â Â Â Â contextDoc = xwikiContext.get(XWIKI_CONTEXT_DOC_KEY);
> + Â Â Â Â // Make sure has prog rights
> + Â Â Â Â xwikiContext.put(XWIKI_CONTEXT_DOC_KEY, docBridge.getDocument(this.componentReference));
> +
> + Â Â Â Â // Perform internal macro transformations.
> + Â Â Â Â macroTransformation.transform(xdom, Syntax.XWIKI_2_0);
> +
> + Â Â Â Â if (methodContext.get(METHOD_CONTEXT_OUTPUT_KEY) != null
> + Â Â Â Â Â Â && ((MethodOutputHandler) methodContext.get(METHOD_CONTEXT_OUTPUT_KEY)).getReturnValue() != null) {
> + Â Â Â Â Â Â return method.getReturnType().cast(((MethodOutputHandler)
> + Â Â Â Â Â Â Â Â methodContext.get(METHOD_CONTEXT_OUTPUT_KEY)).getReturnValue());
> + Â Â Â Â } else if (method.getReturnType().equals(String.class)) {
> + Â Â Â Â Â Â // If return type is String and no specific return value has been provided during the macro
> + Â Â Â Â Â Â // expansion, then we return the content redered as
> + Â Â Â Â Â Â WikiPrinter printer = new DefaultWikiPrinter();
> + Â Â Â Â Â Â BlockRenderer renderer = componentManager.lookup(BlockRenderer.class, Syntax.PLAIN_1_0.toIdString());
> + Â Â Â Â Â Â renderer.render(xdom, printer);
> + Â Â Â Â Â Â return printer.toString();
> + Â Â Â Â } else {
> + Â Â Â Â Â Â // surrender
> + Â Â Â Â Â Â return null;
> + Â Â Â Â }
> + Â Â }
Don't do the same mistake than wik macros (see
http://jira.xwiki.org/jira/browse/XWIKI-5030), you should store the
XDOM instead of the source to avoid reparsing it each time you execute
a virtual method.
> +
> + Â Â /**
> + Â Â * Proxies a method of the {@link Object} class.
> + Â Â *
> + Â Â * @param proxy the proxy instance
> + Â Â * @param method the method to proxy
> + Â Â * @param args possible arguments to the method invocation
> + Â Â * @return the result of the proxied call
> + Â Â */
> + Â Â private Object proxyObjectMethod(Object proxy, Method method, Object[] args)
> + Â Â {
> + Â Â Â Â if (method.equals(hashCodeMethod)) {
> + Â Â Â Â Â Â return proxyHashCode(proxy);
> + Â Â Â Â } else if (method.equals(equalsMethod)) {
> + Â Â Â Â Â Â return proxyEquals(proxy, args[0]);
> + Â Â Â Â } else if (method.equals(toStringMethod)) {
> + Â Â Â Â Â Â return proxyToString(proxy);
> + Â Â Â Â } else {
> + Â Â Â Â Â Â throw new InternalError("unexpected Object method dispatched: " + method);
> + Â Â Â Â }
> + Â Â }
> +
> + Â Â /**
> + Â Â * Default behavior for {@link Object#hashCode()} when not overridden in the wiki component definition.
> + Â Â *
> + Â Â * @param proxy the proxy object
> + Â Â * @return a hash code for the proxy object, as if using standard {Object{@link #hashCode()}.
> + Â Â */
> + Â Â protected Integer proxyHashCode(Object proxy)
> + Â Â {
> + Â Â Â Â return new Integer(System.identityHashCode(proxy));
> + Â Â }
> +
> + Â Â /**
> + Â Â * Default behavior for {@link Object#equals(Object)} when not overridden in the wiki component definition.
> + Â Â *
> + Â Â * @param proxy the proxy object
> + Â Â * @param other the other object of the comparison
> + Â Â * @return the result of the equality comparison between the passed proxy and other object
> + Â Â */
> + Â Â protected Boolean proxyEquals(Object proxy, Object other)
> + Â Â {
> + Â Â Â Â return (proxy == other ? Boolean.TRUE : Boolean.FALSE);
> + Â Â }
> +
> + Â Â /**
> + Â Â * Default behavior for {@link Object#toString()} when not overridden in the wiki component definition.
> + Â Â *
> + Â Â * @param proxy the proxy object
> + Â Â * @return the String representation of the passed proxy object
> + Â Â */
> + Â Â protected String proxyToString(Object proxy)
> + Â Â {
> + Â Â Â Â return proxy.getClass().getName() + '@' + Integer.toHexString(proxy.hashCode());
> + Â Â }
> +
> +}
>
> Added: contrib/sandbox/xwiki-wiki-components/src/main/java/org/xwiki/component/wiki/WikiComponentManager.java
> ===================================================================
> --- contrib/sandbox/xwiki-wiki-components/src/main/java/org/xwiki/component/wiki/WikiComponentManager.java                (rev 0)
> +++ contrib/sandbox/xwiki-wiki-components/src/main/java/org/xwiki/component/wiki/WikiComponentManager.java    2010-05-15 15:08:25 UTC (rev 28878)
> @@ -0,0 +1,46 @@
[...]
> +package org.xwiki.component.wiki;
> +
> +import org.xwiki.component.annotation.ComponentRole;
> +
> +/**
> + * A WikiComponentManager is responsible for registering and unregistering components that are defined as wiki pages.
> + * Each {@link WikiComponent} managed by such manager is associated to a {@link org.xwiki.model.DocumentReference}. The
> + * referred document contains XObjects that define the role, hint and behavior (method bodies) of the component. This
> + * document may also define requirements (other components to be binded in the method bodies execution context) and
> + * possible extra interfaces (for example to implement {@link org.xwiki.component.phase.Initializable}).
> + *
> + * @since 2.4-M2
> + * @version $Id$
> + */
> +@ComponentRole
> +public interface WikiComponentManager
> +{
> +
> + Â Â /**
> + Â Â * Registers the passed component against the underlying component repository.
> + Â Â *
> + Â Â * @param component the component to register
> + Â Â * @throws WikiComponentException when failed to register the component against the CM
> + Â Â */
> + Â Â void registerWikiComponent(WikiComponent component) throws WikiComponentException;
> +
> +}
>
> Added: contrib/sandbox/xwiki-wiki-components/src/main/java/org/xwiki/component/wiki/internal/DefaultMethodOutputHandler.java
> ===================================================================
> --- contrib/sandbox/xwiki-wiki-components/src/main/java/org/xwiki/component/wiki/internal/DefaultMethodOutputHandler.java                (rev 0)
> +++ contrib/sandbox/xwiki-wiki-components/src/main/java/org/xwiki/component/wiki/internal/DefaultMethodOutputHandler.java    2010-05-15 15:08:25 UTC (rev 28878)
> @@ -0,0 +1,54 @@
[...]
> +package org.xwiki.component.wiki.internal;
> +
> +import org.xwiki.component.wiki.MethodOutputHandler;
> +
> +/**
> + * Default method output handler.
> + *
> + * @since 2.4-M2
> + * @version $Id$
> + */
> +public class DefaultMethodOutputHandler implements MethodOutputHandler
> +{
> +
> + Â Â /**
> + Â Â * The stored return value.
> + Â Â */
> + Â Â private Object returnValue;
> +
> + Â Â /**
> + Â Â * {@inheritDoc}
> + Â Â */
> + Â Â public void returnValue(Object value)
> + Â Â {
> + Â Â Â Â this.returnValue = value;
> + Â Â }
> +
> + Â Â /**
> + Â Â * {@inheritDoc}
> + Â Â */
> + Â Â public Object getReturnValue()
> + Â Â {
> + Â Â Â Â return this.returnValue;
> + Â Â }
> +
> +}
>
> Added: contrib/sandbox/xwiki-wiki-components/src/main/java/org/xwiki/component/wiki/internal/DefaultWikiComponent.java
> ===================================================================
> --- contrib/sandbox/xwiki-wiki-components/src/main/java/org/xwiki/component/wiki/internal/DefaultWikiComponent.java               (rev 0)
> +++ contrib/sandbox/xwiki-wiki-components/src/main/java/org/xwiki/component/wiki/internal/DefaultWikiComponent.java   2010-05-15 15:08:25 UTC (rev 28878)
> @@ -0,0 +1,139 @@
[...]
> +package org.xwiki.component.wiki.internal;
> +
> +import java.util.HashMap;
> +import java.util.Map;
> +
> +import org.xwiki.component.wiki.WikiComponent;
> +import org.xwiki.model.reference.DocumentReference;
> +
> +/**
> + * Default implementation of a wiki component definition.
> + *
> + * @since 2.4-M2
> + * @version $Id$
> + */
> +public class DefaultWikiComponent implements WikiComponent
> +{
> + Â Â /**
> + Â Â * @see {@link #getDocumentReference()}
> + Â Â */
> + Â Â private DocumentReference documentReference;
> +
> + Â Â /**
> + Â Â * @see {@link #getHandledMethods()}
> + Â Â */
> + Â Â private Map<String, String> handledMethods = new HashMap<String, String>();
> +
> + Â Â /**
> + Â Â * @see {@link #getRole()}
> + Â Â */
> + Â Â private Class< ? > role;
> +
> + Â Â /**
> + Â Â * @see {@link #getRoleHint()}
> + Â Â */
> + Â Â private String roleHint;
> +
> + Â Â /**
> + Â Â * @see {@link #getImplementedInterfaces()}
> + Â Â */
> + Â Â private Class< ? >[] implementedInterfaces = new Class< ? >[]{};
> +
> + Â Â /**
> + Â Â * Constructor of this component.
> + Â Â *
> + Â Â * @param reference the document holding the component definition
> + Â Â * @param role the role implemented
> + Â Â * @param roleHint the role hint for this role implementation
> + Â Â */
> + Â Â public DefaultWikiComponent(DocumentReference reference, Class< ? > role, String roleHint)
> + Â Â {
> + Â Â Â Â this.documentReference = reference;
> + Â Â Â Â this.role = role;
> + Â Â Â Â this.roleHint = roleHint;
> + Â Â }
> +
> + Â Â /**
> + Â Â * {@inheritDoc}
> + Â Â */
> + Â Â public DocumentReference getDocumentReference()
> + Â Â {
> + Â Â Â Â return this.documentReference;
> + Â Â }
> +
> + Â Â /**
> + Â Â * {@inheritDoc}
> + Â Â */
> + Â Â public Map<String, String> getHandledMethods()
> + Â Â {
> + Â Â Â Â return this.handledMethods;
> + Â Â }
> +
> + Â Â /**
> + Â Â * {@inheritDoc}
> + Â Â */
> + Â Â public Class< ? > getRole()
> + Â Â {
> + Â Â Â Â return this.role;
> + Â Â }
> +
> + Â Â /**
> + Â Â * {@inheritDoc}
> + Â Â */
> + Â Â public String getRoleHint()
> + Â Â {
> + Â Â Â Â return this.roleHint;
> + Â Â }
> +
> + Â Â /**
> + Â Â * {@inheritDoc}
> + Â Â */
> + Â Â public Class< ? >[] getImplementedInterfaces()
> + Â Â {
> + Â Â Â Â return this.implementedInterfaces;
> + Â Â }
> +
> + Â Â /**
> + Â Â * Sets the handled method.
> + Â Â *
> + Â Â * @see {@link #getHandledMethods()}
> + Â Â *
> + Â Â * @param methods the methods this component will handle
> + Â Â */
> + Â Â public void setHandledMethods(Map<String, String> methods)
> + Â Â {
> + Â Â Â Â this.handledMethods = methods;
> + Â Â }
> +
> + Â Â /**
> + Â Â * Sets the implemented interfaces.
> + Â Â *
> + Â Â * @see {@link #getImplementedInterfaces()}
> + Â Â *
> + Â Â * @param interfaces the interfaces this component will implement.
> + Â Â */
> + Â Â public void setImplementedInterfaces(Class< ? >[] interfaces)
> + Â Â {
> + Â Â Â Â this.implementedInterfaces = interfaces;
> + Â Â }
> +
> +}
>
> Added: contrib/sandbox/xwiki-wiki-components/src/main/java/org/xwiki/component/wiki/internal/DefaultWikiComponentManager.java
> ===================================================================
> --- contrib/sandbox/xwiki-wiki-components/src/main/java/org/xwiki/component/wiki/internal/DefaultWikiComponentManager.java                (rev 0)
> +++ contrib/sandbox/xwiki-wiki-components/src/main/java/org/xwiki/component/wiki/internal/DefaultWikiComponentManager.java    2010-05-15 15:08:25 UTC (rev 28878)
> @@ -0,0 +1,130 @@
[...]
> +
> +/**
> + * Default implementation of {@link WikiComponentManager}. Creates proxy objects which method invocation handler keeps a
> + * reference on a set of declared method and associated wiki content to "execute".
> + *
> + * @since 2.4-M2
> + * @version $Id$
> + */
> +@Component
> +public class DefaultWikiComponentManager extends AbstractLogEnabled implements WikiComponentManager
> +{
> + Â Â /**
> + Â Â * Component manager against which wiki component will be registered.
> + Â Â */
> + Â Â @Requirement
> + Â Â private ComponentManager mainComponentManager;
> +
> + Â Â /**
> + Â Â * {@inheritDoc}
> + Â Â */
> + Â Â @SuppressWarnings("unchecked")
> + Â Â public void registerWikiComponent(WikiComponent component) throws WikiComponentException
> + Â Â {
> + Â Â Â Â try {
> + Â Â Â Â Â Â // Get the component role interface
> + Â Â Â Â Â Â Class< ? > role = component.getRole();
> +
> + Â Â Â Â Â Â // Create the method invocation handler of the proxy
> + Â Â Â Â Â Â InvocationHandler handler =
> + Â Â Â Â Â Â Â Â new WikiComponentInvocationHandler(component.getDocumentReference(), component.getHandledMethods(),
> + Â Â Â Â Â Â Â Â Â Â mainComponentManager);
> +
> + Â Â Â Â Â Â // Prepare array of all interfaces the component implementation declares, that is the interface declared as
> + Â Â Â Â Â Â // component role
> + Â Â Â Â Â Â // plus possible extra other interfaces
> + Â Â Â Â Â Â Class< ? >[] allImplementedInterfaces = new Class< ? >[component.getImplementedInterfaces().length + 1];
> + Â Â Â Â Â Â System.arraycopy(component.getImplementedInterfaces(), 0, allImplementedInterfaces, 0, component
> + Â Â Â Â Â Â Â Â .getImplementedInterfaces().length);
> + Â Â Â Â Â Â allImplementedInterfaces[component.getImplementedInterfaces().length] = role;
> +
> + Â Â Â Â Â Â // Create the component instance and its descritor
> + Â Â Â Â Â Â Object instance = Proxy.newProxyInstance(role.getClassLoader(), allImplementedInterfaces, handler);
> + Â Â Â Â Â Â ComponentDescriptor componentDescriptor = this.createComponentDescriptor(role, component.getRoleHint());
> +
> + Â Â Â Â Â Â // Since we are responsible to create the component instance,
> + Â Â Â Â Â Â // we also are responsible of its initialization (if needed)
> + Â Â Â Â Â Â if (this.isInitializable(allImplementedInterfaces)) {
> + Â Â Â Â Â Â Â Â try {
> + Â Â Â Â Â Â Â Â Â Â ((Initializable) instance).initialize();
> + Â Â Â Â Â Â Â Â } catch (InitializationException e) {
> + Â Â Â Â Â Â Â Â Â Â getLogger().error("Failed to initialize wiki component", e);
> + Â Â Â Â Â Â Â Â }
> + Â Â Â Â Â Â }
> +
> + Â Â Â Â Â Â // Finally, register the component against the CM
> + Â Â Â Â Â Â this.mainComponentManager.registerComponent(componentDescriptor, role.cast(instance));
> + Â Â Â Â } catch (ComponentRepositoryException e) {
> + Â Â Â Â Â Â throw new WikiComponentException("Failed to register wiki component against component repository", e);
> + Â Â Â Â }
> + Â Â }
> +
> + Â Â /**
> + Â Â * Helper method to create a component descriptor from role and hint.
> + Â Â *
> + Â Â * @param role the component role of the descriptor to create
> + Â Â * @param roleHint the hint of the implementation for the descriptor to create
> + Â Â * @return the constructed {@link ComponentDescriptor}
> + Â Â */
> + Â Â @SuppressWarnings("unchecked")
> + Â Â private ComponentDescriptor createComponentDescriptor(Class role, String roleHint)
> + Â Â {
> + Â Â Â Â DefaultComponentDescriptor cd = new DefaultComponentDescriptor();
> + Â Â Â Â cd.setRole(role);
> + Â Â Â Â cd.setRoleHint(roleHint);
> + Â Â Â Â return cd;
> + Â Â }
> +
> + Â Â /**
> + Â Â * Helper method that checks if at least one of an array of interfaces is the {@link Initializable} class.
> + Â Â *
> + Â Â * @param interfaces the array of interfaces to test
> + Â Â * @return true if at least one of the passed interfaces is the is the {@link Initializable} class.
> + Â Â */
> + Â Â private boolean isInitializable(Class< ? >[] interfaces)
> + Â Â {
> + Â Â Â Â for (Class< ? > iface : interfaces) {
> + Â Â Â Â Â Â if (Initializable.class.equals(iface)) {
> + Â Â Â Â Â Â Â Â return true;
> + Â Â Â Â Â Â }
> + Â Â Â Â }
> + Â Â Â Â return false;
> + Â Â }
> +}
>
[...]
>
> Added: contrib/sandbox/xwiki-wiki-components/src/test/java/org/xwiki/component/wiki/WikiComponentManagerTest.java
> ===================================================================
> --- contrib/sandbox/xwiki-wiki-components/src/test/java/org/xwiki/component/wiki/WikiComponentManagerTest.java              (rev 0)
> +++ contrib/sandbox/xwiki-wiki-components/src/test/java/org/xwiki/component/wiki/WikiComponentManagerTest.java  2010-05-15 15:08:25 UTC (rev 28878)
> @@ -0,0 +1,34 @@
[...]
> +
> +public class WikiComponentManagerTest extends AbstractComponentTestCase
> +{
> + Â Â private WikiComponentManager manager;
> +
> + Â Â @Before
> + Â Â public void setUp() throws Exception
> + Â Â {
> + Â Â Â Â manager = getComponentManager().lookup(WikiComponentManager.class);
> + Â Â }
> +
> + Â Â @Test
> + Â Â public void testRegisterWikiComponent() throws Exception
> + Â Â {
> + Â Â Â Â DocumentReference pseudoReference = new DocumentReference("somewiki","XWiki","MyComponent");
> +
> + Â Â Â Â DefaultWikiComponent wc = new DefaultWikiComponent(pseudoReference, WikiComponentManager.class, "test");
> +
> + Â Â Â Â this.manager.registerWikiComponent(wc);
> +
> + Â Â Â Â WikiComponentManager registered = this.getComponentManager().lookup(WikiComponentManager.class, "test");
> +
> + Â Â Â Â Assert.assertNotNull(registered);
> + Â Â }
> +}
--
Thomas Mortagne
Hi Devs,
I'd like to add a bridge event to allow components to get notified when
old core has been initialized (at the end of XWiki#initXWiki for example).
This would be useful for components that needs to access the store, for
example to register XWiki classes.
I recognize this solution is not perfect since it's more bridged code, but
it would be better that what we have been doing so far (hard-coded
component initialization in XWiki.java, for example for the wiki macro
bridge to register its classes)
I've attached a patch proposal to
http://jira.xwiki.org/jira/browse/XWIKI-5194.
Note that I would also fix the wiki macro bridge initialization.
+1 from me to go ahead with that.
WDYT ?
Thanks,
Jerome
Hi devs,
I would like to commit my configuration based rendering cache system before
2.4M1 for it to be well tested and improved during 2.4 dev.
You can find details about it on
http://markmail.org/message/tnggdulplm73cxm5
Here is my +1
Thanks,
--
Thomas Mortagne
I'd like to know if this behavior is correct/desired.
1. Users without PR can register skins.
2. Skins can override global velocity macros.
3. Macros are evaluated in the security context of the caller.
If the answer to these questions is yes, then a document which
invokes a global macro such as #livetable does not know that the
macro may be overridden by the skin and it may be doing something in
their name which is a security gotcha and should be loudly documented.
If this behavior is not desired then maybe the best solution is to
prevent skin macros from overriding global macros unless the skin
author has PR.
WDYT?
Caleb
Hi devs,
I want to add a control to choose the page size of livetables. I have made a
proposal, and Guillaume Lerouge has suggested to show it by the default when
using the #livetable macro. This addition is not intrusive, takes no
additional place in the UI and does not require additional support on the
server side.
My updated proposal is resumed here:
http://incubator.myxwiki.org/xwiki/bin/view/Improvements/LivetablePageSizer
I would like to apply this patch for XE2.4M1.
Here is my +1
Denis
--
Denis Gervalle
SOFTEC sa - CEO
eGuilde sarl - CTO
In http://www.mail-archive.com/devs@xwiki.org/msg14717.html
Ludovic said "We need to be as compatible as possible with how the
current invitation manager stores it's configuration and state
(current invitation and requests)"
I think this concept is worthy of it's own discussion thread.
When I approached this project, I hadn't considered a need for an
upgrade path from the Invitation Manager (I assume that's what this
is for.) The application as it stands is quite dependent on a
different configuration/storage model and changing will take a long
time.
Do we really want to use the same configuration/storage as the
Invitation Manager?
* The Invitation Manager plug-in uses configuration parameters
defined in the now deprecated xwiki.cfg file while Invitation
Application uses a custom configuration class through the
XWiki.ConfigurableClass system.
* Invitation Manager and Invitation Application both store message
status as a number, Invitation Application uses additional codes for
"sending failed", "reported as spam", and "reported and investigated".
* Invitation Manager has an additional field "space" which will make
no sense without Space Manager plug-in in the invitation application
setup and will have to be replaced by "groups".
* To copy Invitation Manager setup will block further feature
addition such as invitations which expire after a given amount of
time (for mailing lists).
* Invitation Manager templates are coded in a format similar to
XWiki/1.0 syntax (but not exactly the same) Invitation Application
templates are (currently) to be coded in XWiki/2.0 syntax.
Options:
We could continue the Invitation Application as is and if an upgrade
path is needed, add a script for upgrading legacy data later on.
Drop the current work and get the Invitation Manager plugin to build
(It would be a shame to dump so much work over one requirement.)
Rewrite the current work to be compatible with the old Invitation
Manager, accept using depricated configuration and sacrifice
features (this will take the most time.)
What are your thoughts?
Caleb