Skip to content
Snippets Groups Projects
Commit f6fabf63 authored by Denis Gervalle's avatar Denis Gervalle
Browse files

XWIKI-11037: Content goes blank when annotation are displayed on document bind with a sheet

parent 5ecac8fd
No related branches found
No related tags found
No related merge requests found
......@@ -568,6 +568,20 @@
<field>xClassEntityReferenceResolver</field>
<justification>Not really an APIs.</justification>
</difference>
<difference>
<differenceType>7012</differenceType>
<className>org/xwiki/annotation/io/IOTargetService</className>
<method>org.xwiki.rendering.block.XDOM getXDOM(java.lang.String)</method>
<justification>The annotation API already needs a larger refactoring, this small fix stay in line
with the existing API and does not deserve the creation of a new (temporary) API.</justification>
</difference>
<difference>
<differenceType>7012</differenceType>
<className>org/xwiki/annotation/io/IOTargetService</className>
<method>org.xwiki.rendering.block.XDOM getXDOM(java.lang.String, java.lang.String)</method>
<justification>The annotation API already needs a larger refactoring, this small fix stay in line
with the existing API and does not deserve the creation of a new (temporary) API.</justification>
</difference>
</ignored>
<excludes>
<exclude>**/internal/**</exclude>
......
......@@ -19,7 +19,6 @@
*/
package org.xwiki.annotation.internal;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
......@@ -40,12 +39,8 @@
import org.xwiki.component.annotation.Component;
import org.xwiki.component.manager.ComponentManager;
import org.xwiki.rendering.block.XDOM;
import org.xwiki.rendering.parser.Parser;
import org.xwiki.rendering.renderer.printer.DefaultWikiPrinter;
import org.xwiki.rendering.renderer.printer.WikiPrinter;
import org.xwiki.rendering.syntax.Syntax;
import org.xwiki.rendering.syntax.SyntaxFactory;
import org.xwiki.rendering.transformation.TransformationManager;
/**
* Default annotation service, using the default {@link IOTargetService} and and {@link IOTargetService}, dispatching
......@@ -65,7 +60,7 @@ public class DefaultAnnotationService implements AnnotationService
private IOService ioService;
/**
* Component manager used to lookup the content alterer needed for the specific document.
* Component manager used to lookup the annotation renderer needed for the specific source.
*/
@Inject
private ComponentManager componentManager;
......@@ -111,21 +106,7 @@ public String getAnnotatedRenderedContent(String sourceReference, String sourceS
Collection<Annotation> annotations) throws AnnotationServiceException
{
try {
String source = targetIoService.getSource(sourceReference);
String sourceSyntaxId = sourceSyntax;
// get if unspecified, get the source from the io service
if (sourceSyntaxId == null) {
sourceSyntaxId = targetIoService.getSourceSyntax(sourceReference);
}
Parser parser = componentManager.getInstance(Parser.class, sourceSyntaxId);
XDOM xdom = parser.parse(new StringReader(source));
// run transformations
SyntaxFactory syntaxFactory = componentManager.getInstance(SyntaxFactory.class);
Syntax sSyntax = syntaxFactory.createSyntaxFromIdString(sourceSyntaxId);
TransformationManager transformationManager = componentManager.getInstance(TransformationManager.class);
transformationManager.performTransformations(xdom, sSyntax);
XDOM xdom = targetIoService.getXDOM(sourceReference, sourceSyntax);
// build the annotations renderer hint for the specified output syntax
String outputSyntaxId = "annotations-" + outputSyntax;
......
......@@ -20,6 +20,7 @@
package org.xwiki.annotation.io;
import org.xwiki.component.annotation.Role;
import org.xwiki.rendering.block.XDOM;
/**
* This service provides functions to operate with annotations targets. It operates with string serialized references to
......@@ -36,7 +37,9 @@ public interface IOTargetService
* @param reference serialized string reference of the content to get the source for
* @return the source of the referenced content
* @throws IOServiceException if any exception occurs when manipulating sources
* @deprecated use {@link #getXDOM(String)}
*/
@Deprecated
String getSource(String reference) throws IOServiceException;
/**
......@@ -45,4 +48,27 @@ public interface IOTargetService
* @throws IOServiceException if any exception occurs when manipulating sources
*/
String getSourceSyntax(String reference) throws IOServiceException;
/**
* @param reference serialized string reference of the content to get the XDOM for
* @return the XDOM of the referenced content
* @throws IOServiceException if any exception occurs when manipulating sources
* @since 6.2
*
* TODO: While we use String for reference to stay in the style of the existing API, it would be better to use
* EntityReference when this API get more largely refactored.
*/
XDOM getXDOM(String reference) throws IOServiceException;
/**
* @param reference serialized string reference of the content to get the XDOM for
* @param syntax the syntax of the source of the referenced content
* @return the XDOM of the referenced content
* @throws IOServiceException if any exception occurs when manipulating sources
* @since 6.2
*
* TODO: While we use String for reference and syntax to stay in the style of the existing API, it would be
* better to use EntityReference and SyntaxId when this API get more largely refactored.
*/
XDOM getXDOM(String reference, String syntax) throws IOServiceException;
}
......@@ -29,7 +29,7 @@
<name>XWiki Platform - Annotations - XWiki Storage Implementation</name>
<packaging>jar</packaging>
<properties>
<xwiki.jacoco.instructionRatio>0.05</xwiki.jacoco.instructionRatio>
<xwiki.jacoco.instructionRatio>0.04</xwiki.jacoco.instructionRatio>
</properties>
<dependencies>
<dependency>
......
......@@ -19,18 +19,34 @@
*/
package org.xwiki.annotation.io.internal;
import java.io.StringReader;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
import org.xwiki.annotation.io.IOServiceException;
import org.xwiki.annotation.io.IOTargetService;
import org.xwiki.annotation.reference.IndexedObjectReference;
import org.xwiki.annotation.reference.TypedStringEntityReferenceResolver;
import org.xwiki.bridge.DocumentAccessBridge;
import org.xwiki.component.annotation.Component;
import org.xwiki.component.manager.ComponentManager;
import org.xwiki.display.internal.DocumentDisplayer;
import org.xwiki.display.internal.DocumentDisplayerParameters;
import org.xwiki.model.EntityType;
import org.xwiki.model.reference.DocumentReference;
import org.xwiki.model.reference.EntityReference;
import org.xwiki.model.reference.EntityReferenceSerializer;
import org.xwiki.model.reference.ObjectPropertyReference;
import org.xwiki.rendering.block.XDOM;
import org.xwiki.rendering.parser.ParseException;
import org.xwiki.rendering.parser.Parser;
import org.xwiki.rendering.syntax.Syntax;
import org.xwiki.rendering.syntax.SyntaxFactory;
import org.xwiki.rendering.transformation.TransformationContext;
import org.xwiki.rendering.transformation.TransformationException;
import org.xwiki.rendering.transformation.TransformationManager;
import com.xpn.xwiki.objects.BaseObjectReference;
/**
* Default {@link IOTargetService} implementation, based on resolving XWiki documents and object properties as
......@@ -46,6 +62,12 @@
@Singleton
public class DefaultIOTargetService implements IOTargetService
{
/**
* Component manager used to lookup the parsers.
*/
@Inject
private ComponentManager componentManager;
/**
* Document access bridge to manipulate xwiki documents.
*/
......@@ -53,16 +75,17 @@ public class DefaultIOTargetService implements IOTargetService
private DocumentAccessBridge dab;
/**
* Entity reference handler to resolve the reference.
* Document displayer.
*/
@Inject
private TypedStringEntityReferenceResolver referenceResolver;
@Named("configured")
private DocumentDisplayer documentDisplayer;
/**
* Default entity reference serializer.
* Entity reference handler to resolve the reference.
*/
@Inject
private EntityReferenceSerializer<String> serializer;
private TypedStringEntityReferenceResolver referenceResolver;
@Override
public String getSource(String reference) throws IOServiceException
......@@ -70,18 +93,9 @@ public String getSource(String reference) throws IOServiceException
try {
EntityReference ref = referenceResolver.resolve(reference, EntityType.DOCUMENT);
if (ref.getType() == EntityType.OBJECT_PROPERTY) {
EntityReference docRef = ref.extractReference(EntityType.DOCUMENT);
// handle this as a reference to an object, parse an indexed object out of this property's parent
IndexedObjectReference objRef = new IndexedObjectReference(ref.getParent());
if (objRef.getObjectNumber() != null) {
return dab.getProperty(serializer.serialize(docRef), objRef.getClassName(),
objRef.getObjectNumber(), ref.getName()).toString();
} else {
return dab.getProperty(serializer.serialize(docRef), objRef.getClassName(), ref.getName())
.toString();
}
return getObjectPropertyContent(new ObjectPropertyReference(ref));
} else if (ref.getType() == EntityType.DOCUMENT) {
return dab.getDocumentContent(serializer.serialize(ref));
return dab.getDocument(new DocumentReference(ref)).getContent();
} else {
// it was parsed as something else, just ignore the parsing and get the document content as its initial
// name was
......@@ -101,7 +115,7 @@ public String getSourceSyntax(String reference) throws IOServiceException
if (docRef != null) {
// return the syntax of the document in this reference, regardless of the type of reference, obj prop or
// doc
return dab.getDocumentSyntaxId(serializer.serialize(docRef));
return dab.getDocument(new DocumentReference(docRef)).getSyntax().toIdString();
} else {
return dab.getDocumentSyntaxId(reference);
}
......@@ -110,4 +124,71 @@ public String getSourceSyntax(String reference) throws IOServiceException
+ reference, e);
}
}
@Override
public XDOM getXDOM(String reference) throws IOServiceException
{
return getXDOM(reference, null);
}
@Override
public XDOM getXDOM(String reference, String syntax) throws IOServiceException
{
String sourceSyntaxId = syntax;
// get if unspecified, get the source from the io service
if (sourceSyntaxId == null) {
sourceSyntaxId = getSourceSyntax(reference);
}
try {
EntityReference ref = referenceResolver.resolve(reference, EntityType.DOCUMENT);
if (ref.getType() == EntityType.OBJECT_PROPERTY) {
return getTransformedXDOM(getObjectPropertyContent(new ObjectPropertyReference(ref)),
sourceSyntaxId);
} else if (ref.getType() == EntityType.DOCUMENT) {
return getDocumentXDOM(new DocumentReference(ref));
} else {
// it was parsed as something else, just ignore the parsing and get the document content as its initial
// name was
return getTransformedXDOM(dab.getDocumentContent(reference), sourceSyntaxId);
}
} catch (Exception e) {
throw new IOServiceException("An exception has occurred while getting the XDOM for " + reference, e);
}
}
private XDOM getDocumentXDOM(DocumentReference reference) throws Exception
{
DocumentDisplayerParameters parameters = new DocumentDisplayerParameters();
parameters.setExecutionContextIsolated(true);
parameters.setContentTranslated(true);
parameters.setTargetSyntax(Syntax.XHTML_1_0);
return documentDisplayer.display(dab.getDocument(reference), parameters);
}
private XDOM getTransformedXDOM(String content, String sourceSyntaxId)
throws ParseException, org.xwiki.component.manager.ComponentLookupException, TransformationException
{
Parser parser = componentManager.getInstance(Parser.class, sourceSyntaxId);
XDOM xdom = parser.parse(new StringReader(content));
// run transformations
SyntaxFactory syntaxFactory = componentManager.getInstance(SyntaxFactory.class);
TransformationContext txContext =
new TransformationContext(xdom, syntaxFactory.createSyntaxFromIdString(sourceSyntaxId));
TransformationManager transformationManager = componentManager.getInstance(TransformationManager.class);
transformationManager.performTransformations(xdom, txContext);
return xdom;
}
private String getObjectPropertyContent(ObjectPropertyReference reference) {
BaseObjectReference objRef = new BaseObjectReference(reference.getParent());
DocumentReference docRef = new DocumentReference(objRef.getParent());
if (objRef.getObjectNumber() != null) {
return dab.getProperty(docRef, objRef.getXClassReference(),
objRef.getObjectNumber(), reference.getName()).toString();
} else {
return dab.getProperty(docRef, objRef.getXClassReference(), reference.getName()).toString();
}
}
}
......@@ -19,14 +19,21 @@
*/
package org.xwiki.annotation.io.internal;
import static org.junit.Assert.assertEquals;
import org.jmock.Expectations;
import org.junit.Test;
import org.xwiki.annotation.io.IOTargetService;
import org.xwiki.bridge.DocumentAccessBridge;
import org.xwiki.bridge.DocumentModelBridge;
import org.xwiki.model.reference.DocumentReference;
import org.xwiki.model.reference.DocumentReferenceResolver;
import org.xwiki.rendering.syntax.Syntax;
import org.xwiki.rendering.syntax.SyntaxType;
import org.xwiki.test.jmock.AbstractComponentTestCase;
import com.xpn.xwiki.web.Utils;
import static org.junit.Assert.assertEquals;
/**
* Tests the default implementation of {@link IOTargetService}, and integration with target resolvers, up to the
* document access bridge access.
......@@ -46,6 +53,11 @@ public class DefaultIOTargetServiceTest extends AbstractComponentTestCase
*/
private DocumentAccessBridge dabMock;
/**
* Mock for DocumentReferenceResolver<String> used by BaseObjectReference
*/
private DocumentReferenceResolver<String> classResolver;
@Override
protected void registerComponents() throws Exception
{
......@@ -53,6 +65,13 @@ protected void registerComponents() throws Exception
// register the dab
this.dabMock = registerMockComponent(DocumentAccessBridge.class);
getMockery().checking(new Expectations()
{
{
allowing(dabMock).getCurrentUserReference();
}
});
this.classResolver = registerMockComponent(DocumentReferenceResolver.TYPE_STRING);
}
@Override
......@@ -62,18 +81,22 @@ public void setUp() throws Exception
// get the default io target service
ioTargetService = getComponentManager().getInstance(IOTargetService.class);
Utils.setComponentManager(getComponentManager());
}
@Test
public void testGettersWhenTargetIsTypedDocument() throws Exception
{
final DocumentModelBridge dmb = getMockery().mock(DocumentModelBridge.class);
getMockery().checking(new Expectations()
{
{
oneOf(dabMock).getDocumentContent("wiki:Space.Page");
allowing(dabMock).getDocument(new DocumentReference("wiki", "Space", "Page"));
will(returnValue(dmb));
oneOf(dmb).getContent();
will(returnValue("defcontent"));
oneOf(dabMock).getDocumentSyntaxId("wiki:Space.Page");
will(returnValue("xwiki/2.0"));
oneOf(dmb).getSyntax();
will(returnValue(new Syntax(SyntaxType.XWIKI,"2.0")));
}
});
......@@ -85,13 +108,16 @@ public void testGettersWhenTargetIsTypedDocument() throws Exception
@Test
public void testGettersWhenTargetIsNonTypedDocument() throws Exception
{
final DocumentModelBridge dmb = getMockery().mock(DocumentModelBridge.class);
getMockery().checking(new Expectations()
{
{
oneOf(dabMock).getDocumentContent("wiki:Space.Page");
allowing(dabMock).getDocument(new DocumentReference("wiki", "Space", "Page"));
will(returnValue(dmb));
oneOf(dmb).getContent();
will(returnValue("defcontent"));
oneOf(dabMock).getDocumentSyntaxId("wiki:Space.Page");
will(returnValue("xwiki/2.0"));
oneOf(dmb).getSyntax();
will(returnValue(new Syntax(SyntaxType.XWIKI,"2.0")));
}
});
......@@ -103,14 +129,17 @@ public void testGettersWhenTargetIsNonTypedDocument() throws Exception
@Test
public void testGettersWhenTargetIsNonTypedRelativeDocument() throws Exception
{
final DocumentModelBridge dmb = getMockery().mock(DocumentModelBridge.class);
getMockery().checking(new Expectations()
{
{
// default resolver should be used
oneOf(dabMock).getDocumentContent("xwiki:Space.Page");
allowing(dabMock).getDocument(new DocumentReference("xwiki", "Space", "Page"));
will(returnValue(dmb));
oneOf(dmb).getContent();
will(returnValue("defcontent"));
oneOf(dabMock).getDocumentSyntaxId("xwiki:Space.Page");
will(returnValue("xwiki/2.0"));
oneOf(dmb).getSyntax();
will(returnValue(new Syntax(SyntaxType.XWIKI,"2.0")));
}
});
......@@ -122,14 +151,17 @@ public void testGettersWhenTargetIsNonTypedRelativeDocument() throws Exception
@Test
public void testGettersWhenTargetIsTypedRelativeDocument() throws Exception
{
final DocumentModelBridge dmb = getMockery().mock(DocumentModelBridge.class);
getMockery().checking(new Expectations()
{
{
// default resolver should be used
oneOf(dabMock).getDocumentContent("xwiki:Space.Page");
allowing(dabMock).getDocument(new DocumentReference("xwiki", "Space", "Page"));
will(returnValue(dmb));
oneOf(dmb).getContent();
will(returnValue("defcontent"));
oneOf(dabMock).getDocumentSyntaxId("xwiki:Space.Page");
will(returnValue("xwiki/2.0"));
oneOf(dmb).getSyntax();
will(returnValue(new Syntax(SyntaxType.XWIKI,"2.0")));
}
});
......@@ -141,6 +173,7 @@ public void testGettersWhenTargetIsTypedRelativeDocument() throws Exception
@Test
public void testGettersWhenTargetIsTypedSpace() throws Exception
{
final DocumentModelBridge dmb = getMockery().mock(DocumentModelBridge.class);
getMockery().checking(new Expectations()
{
{
......@@ -161,15 +194,18 @@ public void testGettersWhenTargetIsTypedSpace() throws Exception
@Test
public void testGettersWhenTargetIsEmptyString() throws Exception
{
final DocumentModelBridge dmb = getMockery().mock(DocumentModelBridge.class);
getMockery().checking(new Expectations()
{
{
// default resolver should be used. Note that this will fail if default values change, not very well
// isolated
oneOf(dabMock).getDocumentContent("xwiki:Main.WebHome");
allowing(dabMock).getDocument(new DocumentReference("xwiki", "Main", "WebHome"));
will(returnValue(dmb));
oneOf(dmb).getContent();
will(returnValue("defcontent"));
oneOf(dabMock).getDocumentSyntaxId("xwiki:Main.WebHome");
will(returnValue("xwiki/2.0"));
oneOf(dmb).getSyntax();
will(returnValue(new Syntax(SyntaxType.XWIKI,"2.0")));
}
});
......@@ -182,13 +218,19 @@ public void testGettersWhenTargetIsEmptyString() throws Exception
@Test
public void testGetterWhenTargetIsTypedIndexedObjectProperty() throws Exception
{
final DocumentModelBridge dmb = getMockery().mock(DocumentModelBridge.class);
getMockery().checking(new Expectations()
{
{
oneOf(dabMock).getProperty("wiki:Space.Page", "XWiki.Class", 1, "property");
allowing(classResolver).resolve("XWiki.Class");
will(returnValue(new DocumentReference("wiki", "XWiki", "Class")));
oneOf(dabMock).getProperty(new DocumentReference("wiki", "Space", "Page"),
new DocumentReference("wiki", "XWiki", "Class"), 1, "property");
will(returnValue("defcontent"));
oneOf(dabMock).getDocumentSyntaxId("wiki:Space.Page");
will(returnValue("xwiki/2.0"));
oneOf(dabMock).getDocument(new DocumentReference("wiki", "Space", "Page"));
will(returnValue(dmb));
oneOf(dmb).getSyntax();
will(returnValue(new Syntax(SyntaxType.XWIKI,"2.0")));
}
});
......@@ -200,13 +242,19 @@ public void testGetterWhenTargetIsTypedIndexedObjectProperty() throws Exception
@Test
public void testGetterWhenTargetIsTypedDefaultObjectProperty() throws Exception
{
final DocumentModelBridge dmb = getMockery().mock(DocumentModelBridge.class);
getMockery().checking(new Expectations()
{
{
oneOf(dabMock).getProperty("wiki:Space.Page", "XWiki.Class", "property");
allowing(classResolver).resolve("XWiki.Class");
will(returnValue(new DocumentReference("wiki", "XWiki", "Class")));
oneOf(dabMock).getProperty(new DocumentReference("wiki", "Space", "Page"),
new DocumentReference("wiki", "XWiki", "Class"), "property");
will(returnValue("defcontent"));
oneOf(dabMock).getDocumentSyntaxId("wiki:Space.Page");
will(returnValue("xwiki/2.0"));
oneOf(dabMock).getDocument(new DocumentReference("wiki", "Space", "Page"));
will(returnValue(dmb));
oneOf(dmb).getSyntax();
will(returnValue(new Syntax(SyntaxType.XWIKI,"2.0")));
}
});
......@@ -218,13 +266,19 @@ public void testGetterWhenTargetIsTypedDefaultObjectProperty() throws Exception
@Test
public void testGetterWhenTargetIsTypedObjectPropertyInRelativeDocument() throws Exception
{
final DocumentModelBridge dmb = getMockery().mock(DocumentModelBridge.class);
getMockery().checking(new Expectations()
{
{
oneOf(dabMock).getProperty("xwiki:Main.Page", "XWiki.Class", "property");
allowing(classResolver).resolve("XWiki.Class");
will(returnValue(new DocumentReference("xwiki", "XWiki", "Class")));
oneOf(dabMock).getProperty(new DocumentReference("xwiki", "Main", "Page"),
new DocumentReference("xwiki", "XWiki", "Class"), "property");
will(returnValue("defcontent"));
oneOf(dabMock).getDocumentSyntaxId("xwiki:Main.Page");
will(returnValue("xwiki/2.0"));
oneOf(dabMock).getDocument(new DocumentReference("xwiki", "Main", "Page"));
will(returnValue(dmb));
oneOf(dmb).getSyntax();
will(returnValue(new Syntax(SyntaxType.XWIKI,"2.0")));
}
});
......@@ -236,14 +290,17 @@ public void testGetterWhenTargetIsTypedObjectPropertyInRelativeDocument() throws
@Test
public void testGetterWhenTargetIsNonTypedObjectProperty() throws Exception
{
final DocumentModelBridge dmb = getMockery().mock(DocumentModelBridge.class);
getMockery().checking(new Expectations()
{
{
// target will be parsed as document, because document is the default
oneOf(dabMock).getDocumentContent("wiki:Space\\.Page^XWiki\\.Class.property");
allowing(dabMock).getDocument(new DocumentReference("wiki", "Space.Page^XWiki.Class", "property"));
will(returnValue(dmb));
oneOf(dmb).getContent();
will(returnValue("defcontent"));
oneOf(dabMock).getDocumentSyntaxId("wiki:Space\\.Page^XWiki\\.Class.property");
will(returnValue("xwiki/2.0"));
oneOf(dmb).getSyntax();
will(returnValue(new Syntax(SyntaxType.XWIKI,"2.0")));
}
});
......@@ -255,14 +312,20 @@ public void testGetterWhenTargetIsNonTypedObjectProperty() throws Exception
@Test
public void testGetterWhenTargetIsTypedIndexedRelativeObjectProperty() throws Exception
{
final DocumentModelBridge dmb = getMockery().mock(DocumentModelBridge.class);
getMockery().checking(new Expectations()
{
{
// this will fail if defaults fail, not very well isolated
oneOf(dabMock).getProperty("xwiki:Main.WebHome", "Classes.Class", 3, "property");
allowing(classResolver).resolve("Classes.Class");
will(returnValue(new DocumentReference("xwiki", "Classes", "Class")));
oneOf(dabMock).getProperty(new DocumentReference("xwiki", "Main", "WebHome"),
new DocumentReference("xwiki", "Classes", "Class"), 3, "property");
will(returnValue("defcontent"));
oneOf(dabMock).getDocumentSyntaxId("xwiki:Main.WebHome");
will(returnValue("xwiki/2.0"));
oneOf(dabMock).getDocument(new DocumentReference("xwiki", "Main", "WebHome"));
will(returnValue(dmb));
oneOf(dmb).getSyntax();
will(returnValue(new Syntax(SyntaxType.XWIKI,"2.0")));
}
});
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment