Re: [xwiki-devs] [xwiki-notifications] r28878 - in contrib/sandbox: . xwiki-wiki-components xwiki-wiki-components/src xwiki-wiki-components/src/main xwiki-wiki-components/src/main/java xwiki-wiki-components/src/main/java/com xwiki-wiki-components/src
16 May
2010
16 May
'10
2:03 p.m.
On Sun, May 16, 2010 at 15:25, Jerome Velociter <jerome@xwiki.com> wrote:
>
> ----- "Thomas Mortagne" <thomas.mortagne@xwiki.com> wrote:
>
>> On Sat, May 15, 2010 at 17:08, jvelociter
>> <contrib-notifications@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.
>
> Right. It's actually doing so already (throwing NoSuchMethodException).
>
> I think the question still holds, though. We could decide to enforce compliance to the interface in order to allow a component to be registered (would reduce collateral damage for components relying on that role - like the OM interacting with an EventListener not declaring onEvent)
Yes probably, sounds weird to implements an incomplete component.
>
>>
>> > - 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.
>
> OK. Will take care of that.
>
> Jerome.
>
>>
>> > +
>> > + /**
>> > + * 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
>> _______________________________________________
>> devs mailing list
>> devs@xwiki.org
>> http://lists.xwiki.org/mailman/listinfo/devs
> _______________________________________________
> devs mailing list
> devs@xwiki.org
> http://lists.xwiki.org/mailman/listinfo/devs
>
--
Thomas Mortagne
5947
Age (days ago)
5947
Last active (days ago)
0 comments
1 participants
participants (1)
-
Thomas Mortagne