xwiki-devs
Threads by month
- ----- 2026 -----
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2006 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2005 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
May 2010
- 30 participants
- 85 discussions
Hi developers,
A while ago I was looking for some ways to track how much memory is used
by our internal cache and was not able to find anything.
I've tried it again and this time I found the following code:
http://www.javamex.com/classmexer/
This requires a simple instrumentation to work, but I was able to get
some results out of it to measure the size of our documents in cache.
You can see the result on a personal server:
Measuring one page:
http://www.zapnews.tv/xwiki/bin/view/Admin/MemoryUsage
Measuring all pages in cache:
http://www.zapnews.tv/xwiki/bin/view/Admin/MemoryUsage?page=all
The first results I can see, is that with no surprise the items taking
most memory are:
- attachment content
- attachment archive
- archive
What I was able to see is that as expected these fields won't consume
memory until we are asking for the data.
And after a while, the memory is indeed discarded for these fields, so
the usage of SoftReferences for them seem to work.
Now what I can see is that the attachment archive can be very very very
costly in memory.
Also it does not seem clear how the memory from these fields is garbage
collected (a GC did not recover it).
With some experience of massive loading of attachments that lead to
OutOfMemory errors in the server, I do suspect that the SoftReferences
are not necessarly discarded fast enough to avoid the OutOfMemory. I
also believe that a search engine that is walking all our pages
including our archive pages can genearate important memory usage that
could lead to problems. But this is only an intuition that needs to be
proved.
I believe we need to run some testing under stress to see if the cache
and memory usage do behave properly and if the cache(s) are never able
to go over the memory usage.
We also should try the classmexer on servers that are heavily used an be
able to look at the memory usage and see if we are "controling" it. I'm
not 100% sure how intrusive the "instrumentation" module is but I
believe it's quite light.
We could try it on xwiki.org or on myxwiki.org.
WDYT ?
Ludovic
--
Ludovic Dubost
Blog:http://blog.ludovic.org/
XWiki:http://www.xwiki.com
Skype: ldubost GTalk: ldubost
2
4
Re: [xwiki-devs] [xwiki-notifications] r28930 - platform/xwiki-tools/trunk/xwiki-configuration-resources/src/main/resources
by Vincent Massol 17 May '10
by Vincent Massol 17 May '10
17 May '10
On May 17, 2010, at 2:38 PM, tmortagne (SVN) wrote:
> Author: tmortagne
> Date: 2010-05-17 14:38:00 +0200 (Mon, 17 May 2010)
> New Revision: 28930
>
> Modified:
> platform/xwiki-tools/trunk/xwiki-configuration-resources/src/main/resources/xwiki.properties.vm
> Log:
> XTCONFRES-48: Add configuration for document rendering cache
>
> Modified: platform/xwiki-tools/trunk/xwiki-configuration-resources/src/main/resources/xwiki.properties.vm
> ===================================================================
> --- platform/xwiki-tools/trunk/xwiki-configuration-resources/src/main/resources/xwiki.properties.vm 2010-05-17 12:33:16 UTC (rev 28929)
> +++ platform/xwiki-tools/trunk/xwiki-configuration-resources/src/main/resources/xwiki.properties.vm 2010-05-17 12:38:00 UTC (rev 28930)
> @@ -12,6 +12,27 @@
> #-# Default value is xwiki/2.0.
> # core.defaultDocumentSyntax = xwiki/1.0
>
> +#-# [Since 2.4M1]
> +#-# Indicate if the rendering cache is enabled.
> +#-# Default value is false.
> +# core.renderingcache.enabled=true
> +
> +#-# [Since 2.4M1]
> +#-# A list of JAVA regex based patterns matching full documents reference.
Is this param about listing documents that are cached and for which the rendered result is cached? If so I think we should mention this in the documentation.
Also JAVA --> Java ? (uppercase would mean that it's an acronym, which it isn't).
"JAVA regex based" --> "Java regex" ?
> +# core.renderingcache.documents=wiki:Space\.Page
> +# core.renderingcache.documents=wiki:Space\..*
> +
> +#-# [Since 2.4M1]
> +#-# Indicate after which duration (in seconds) a data should be removed from the cache when not used.
"The time after which data should be removed from the cache when not used."
> +#-# Default value is 300 (5 min).
> +# core.renderingcache.duration=300
> +
> +#-# [Since 2.4M1]
> +#-# The size of the rendering cache. Not that its not the number of document cached but the number of results cached.
"its" --> "it's"
"document" --> "documents"
"document cached" --> "cached documents"
"results cached" --> "cached results"
> +#-# For a same document a variety of result is produced because each action, language and request query string produce unique result.
I would put this in parenthesis to mention that it's an explanation of "results" above.
Also:
"For a same document a variety of result is produced because each action, language and request query string produce unique result."
-->
"For a single document several cache entries are created, because each action, language and request query string produces a unique rendering result."
> +#-# Default value is 100.
> +# core.renderingcache.size=100
> +
> #-------------------------------------------------------------------------------------
> # Rendering
> #-------------------------------------------------------------------------------------
>
Thanks
-Vincent
1
0
Re: [xwiki-devs] [xwiki-notifications] r28901 - enterprise/trunk/distribution-test/ui-tests/src/test/it/org/xwiki/it/ui
by Vincent Massol 17 May '10
by Vincent Massol 17 May '10
17 May '10
On May 17, 2010, at 2:34 AM, sdumitriu (SVN) wrote:
> Author: sdumitriu
> Date: 2010-05-17 02:34:18 +0200 (Mon, 17 May 2010)
> New Revision: 28901
>
> Modified:
> enterprise/trunk/distribution-test/ui-tests/src/test/it/org/xwiki/it/ui/EscapeTest.java
> Log:
> [misc] Added a test.
>
> Modified: enterprise/trunk/distribution-test/ui-tests/src/test/it/org/xwiki/it/ui/EscapeTest.java
[snip]
> + /**
> + * Go to a working page after each test run to prevent failures in {@link #setUp()}
> + */
> + @After
> + public void tearDown()
> + {
> + TestUtils.gotoPage("Main", "WebHome", getDriver());
> + }
It's a little bit better to do this in setUp rather than in tearDown, for performance (Each test is responsible to set up a working state).
Thanks
-Vincent
2
2
Re: [xwiki-devs] [xwiki-notifications] r28906 - platform/core/trunk/xwiki-core/src/main/java/com/xpn/xwiki/web
by Vincent Massol 17 May '10
by Vincent Massol 17 May '10
17 May '10
I think I remember Ludovic was using that status action some time ago.
Ludovic, can you confirm it's ok to remove it?
Thanks
-Vincent
On May 17, 2010, at 3:29 AM, sdumitriu (SVN) wrote:
> Author: sdumitriu
> Date: 2010-05-17 03:29:40 +0200 (Mon, 17 May 2010)
> New Revision: 28906
>
> Removed:
> platform/core/trunk/xwiki-core/src/main/java/com/xpn/xwiki/web/StatusAction.java
> Log:
> XWIKI-5200: Remove non-working /status/ action
> Removed Java code.
>
> Deleted: platform/core/trunk/xwiki-core/src/main/java/com/xpn/xwiki/web/StatusAction.java
> ===================================================================
> --- platform/core/trunk/xwiki-core/src/main/java/com/xpn/xwiki/web/StatusAction.java 2010-05-17 01:29:34 UTC (rev 28905)
> +++ platform/core/trunk/xwiki-core/src/main/java/com/xpn/xwiki/web/StatusAction.java 2010-05-17 01:29:40 UTC (rev 28906)
> @@ -1,45 +0,0 @@
> -/*
> - * See the NOTICE file distributed with this work for additional
> - * information regarding copyright ownership.
> - *
> - * This is free software; you can redistribute it and/or modify it
> - * under the terms of the GNU Lesser General Public License as
> - * published by the Free Software Foundation; either version 2.1 of
> - * the License, or (at your option) any later version.
> - *
> - * This software is distributed in the hope that it will be useful,
> - * but WITHOUT ANY WARRANTY; without even the implied warranty of
> - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
> - * Lesser General Public License for more details.
> - *
> - * You should have received a copy of the GNU Lesser General Public
> - * License along with this software; if not, write to the Free
> - * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
> - * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
> - *
> - */
> -package com.xpn.xwiki.web;
> -
> -import com.xpn.xwiki.XWiki;
> -import com.xpn.xwiki.XWikiContext;
> -import org.apache.struts.action.ActionForward;
> -
> -public class StatusAction extends XWikiAction
> -{
> - /**
> - * We override {@link XWikiAction#execute(XWikiContext) since we don't want any database calls
> - * at all to happen during the execution of this action since we're displaying statuses about
> - * the database.
> - */
> - public ActionForward execute(XWikiContext context) throws Exception
> - {
> - // We only get the main wiki since the database statuses are available from it and getting
> - // the other wiki will call the database.
> - XWiki.getMainXWiki(context);
> -
> - String page = Utils.getPage(context.getRequest(), "status");
> - Utils.parseTemplate(page, !page.equals("direct"), context);
> -
> - return null;
> - }
> -}
2
1
Hi devs,
There are several templates and actions that haven't been used in quite
a long time, most of which don't even work anymore. I'd like to remove
them, since they are a burden to maintain and they give the false
impression that some functionality exists and is supposed to work.
Actions to remove:
- /status/, which was supposed to give status information about the
server (memory + database connections), but it doesn't work at all now,
and it would need some major work to make it functional + safe. The same
(and more) functionality is provided by the Monitoring Application.
- /gettables/ /createchart/ /previewchart/ and /chartwizard/, which were
supposed to be used by a chart wizard developed in 2005, but
unmaintained since then, and which don't work anymore. Viewing manually
entered charts still works without these actions.
- /lifeblog/ (and the entire com.xpn.xwiki.atom package) which doesn't
seem to work, since it was written a very long time ago, and uses a lot
of old, not working stuff, like a XWiki.BlogPreferences class and
expects unencrypted passwords.
Templates to remove:
- status.vm, used by the /status/ action
- chwmain.vm, gettables.vm, getpagedatasources.vm and the chw/
directory, used by the non-working chart wizard
- wml.vm, since it offers very little functionality, and nobody really
uses WML anymore
- s5*.vm, used by the old Presentation Application, which was removed
from the default XE and has been unmaintained for a long time
All these probably haven't been used since before XWiki 1.0, and in case
we'll ever need them, they can be found in the SVN history.
--
Sergiu Dumitriu
http://purl.org/net/sergiu/
5
4
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
by Thomas Mortagne 16 May '10
by Thomas Mortagne 16 May '10
16 May '10
On Sun, May 16, 2010 at 15:25, Jerome Velociter <jerome(a)xwiki.com> wrote:
>
> ----- "Thomas Mortagne" <thomas.mortagne(a)xwiki.com> wrote:
>
>> 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.
>
> 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(a)xwiki.org
>> http://lists.xwiki.org/mailman/listinfo/devs
> _______________________________________________
> devs mailing list
> devs(a)xwiki.org
> http://lists.xwiki.org/mailman/listinfo/devs
>
--
Thomas Mortagne
1
0
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/main/java/co
by Jerome Velociter 16 May '10
by Jerome Velociter 16 May '10
16 May '10
----- "Thomas Mortagne" <thomas.mortagne(a)xwiki.com> wrote:
> 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.
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)
>
> > - 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(a)xwiki.org
> http://lists.xwiki.org/mailman/listinfo/devs
1
0
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/main/java/co
by Thomas Mortagne 16 May '10
by Thomas Mortagne 16 May '10
16 May '10
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
1
0
[xwiki-devs] [VOTE] Add bridge event for notifying components XWiki has been initialized (XWIKI-5194)
by Jerome Velociter 16 May '10
by Jerome Velociter 16 May '10
16 May '10
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
3
4
15 May '10
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
5
7