Skip to content
Snippets Groups Projects
Commit 6be15615 authored by Eduard Moraru's avatar Eduard Moraru
Browse files

XWIKI-7677: Add AnnotationConfiguration component to allow consistent...

XWIKI-7677: Add AnnotationConfiguration component to allow consistent retrieval of the Annotation Application's settings
parent 215c2fa6
No related branches found
No related tags found
No related merge requests found
......@@ -61,6 +61,11 @@
<artifactId>xwiki-platform-bridge</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.xwiki.platform</groupId>
<artifactId>xwiki-platform-configuration-default</artifactId>
<version>${project.version}</version>
</dependency>
<!-- Test dependencies -->
<dependency>
......
/*
* 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 org.xwiki.annotation;
import java.util.List;
import org.xwiki.component.annotation.Role;
import org.xwiki.model.reference.DocumentReference;
import org.xwiki.model.reference.SpaceReference;
/**
* The configuration of the Annotations Application.
*
* @version $Id$
* @since 4.0M2
*/
@Role
public interface AnnotationConfiguration
{
/**
* The configuration page's space name.
*/
String CONFIGURATION_PAGE_SPACE_NAME = "AnnotationCode";
/**
* The configuration page's name.
*/
String CONFIGURATION_PAGE_NAME = "AnnotationConfig";
/**
* @return true if the annotations UI is activated, false otherwise.
*/
boolean isActivated();
/**
* @return the list of spaces where the annotations UI should not be displayed.
*/
List<SpaceReference> getExceptionSpaces();
/**
* @return true if annotations are displayed by default in the UI.
*/
boolean isDisplayedByDefault();
/**
* @return true if the annotations should be highlighted by default in the UI.
*/
boolean isDisplayedHighlightedByDefault();
/**
* @return the reference of the XWiki class defining an annotation's structure.
*/
DocumentReference getAnnotationClassReference();
}
/*
* 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 org.xwiki.annotation.internal;
import javax.inject.Named;
import org.xwiki.annotation.AnnotationConfiguration;
import org.xwiki.component.annotation.Component;
import org.xwiki.component.annotation.InstantiationStrategy;
import org.xwiki.component.descriptor.ComponentInstantiationStrategy;
import org.xwiki.configuration.internal.AbstractDocumentConfigurationSource;
import org.xwiki.model.reference.DocumentReference;
/**
* Provides configuration from the Annotation Application's configuration document, for the current wiki. Clients of
* this component should use lazy injection (@see {@link javax.inject.Provider}) in order to always receive the
* configuration of the current wiki.
*
* @version $Id$
* @since 4.0M2
*/
@Component
@Named("annotation")
@InstantiationStrategy(ComponentInstantiationStrategy.PER_LOOKUP)
public class AnnotationConfigurationSource extends AbstractDocumentConfigurationSource
{
@Override
protected DocumentReference getDocumentReference()
{
return new DocumentReference(getCurrentWikiReference().getName(),
AnnotationConfiguration.CONFIGURATION_PAGE_SPACE_NAME, AnnotationConfiguration.CONFIGURATION_PAGE_NAME);
}
@Override
protected DocumentReference getClassReference()
{
return getDocumentReference();
}
}
/*
* 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 org.xwiki.annotation.internal;
import java.util.ArrayList;
import java.util.List;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Provider;
import org.xwiki.annotation.AnnotationConfiguration;
import org.xwiki.configuration.ConfigurationSource;
import org.xwiki.model.EntityType;
import org.xwiki.model.ModelConfiguration;
import org.xwiki.model.ModelContext;
import org.xwiki.model.reference.DocumentReference;
import org.xwiki.model.reference.DocumentReferenceResolver;
import org.xwiki.model.reference.SpaceReference;
import org.xwiki.model.reference.WikiReference;
/**
* Default implementation using as configuration source the configuration document on the current wiki.
*
* @version $Id$
* @since 4.0M2
*/
public class DefaultAnnotationConfiguration implements AnnotationConfiguration
{
/**
* Annotation configuration source that is read from the configuration document on the current wiki.
*/
@Inject
@Named("annotation")
protected Provider<ConfigurationSource> configuration;
/**
* Resolver used to read the string values from the configuration as document references.
*/
@Inject
@Named("currentmixed")
protected DocumentReferenceResolver<String> resolver;
/** @see #getCurrentWikiReference() */
@Inject
private ModelContext modelContext;
/** @see #getCurrentWikiReference() */
@Inject
private ModelConfiguration modelConfig;
@Override
public boolean isActivated()
{
return configuration.get().getProperty("activated");
}
@Override
public List<SpaceReference> getExceptionSpaces()
{
List<String> exceptionSpaces = configuration.get().getProperty("exceptionSpaces", List.class);
List<SpaceReference> result = new ArrayList<SpaceReference>();
for (String exceptionSpace : exceptionSpaces) {
result.add(new SpaceReference(exceptionSpace, getCurrentWikiReference()));
}
return result;
}
@Override
public boolean isDisplayedByDefault()
{
return configuration.get().getProperty("displayed");
}
@Override
public boolean isDisplayedHighlightedByDefault()
{
return configuration.get().getProperty("displayHighlight");
}
@Override
public DocumentReference getAnnotationClassReference()
{
String annotationClassName = configuration.get().getProperty("annotationClass");
return resolver.resolve(annotationClassName);
}
/**
* @return the reference pointing to the current wiki
*/
protected WikiReference getCurrentWikiReference()
{
if (this.modelContext.getCurrentEntityReference() != null) {
return (WikiReference) this.modelContext.getCurrentEntityReference().extractReference(EntityType.WIKI);
}
return new WikiReference(this.modelConfig.getDefaultReferenceValue(EntityType.WIKI));
}
}
org.xwiki.annotation.internal.AnnotationConfigurationSource
org.xwiki.annotation.internal.DefaultAnnotationConfiguration
org.xwiki.annotation.internal.DefaultAnnotationService
org.xwiki.annotation.internal.content.WhiteSpaceContentAlterer
org.xwiki.annotation.internal.content.SpaceNormalizerContentAlterer
......
......@@ -32,6 +32,7 @@
import org.slf4j.Logger;
import org.xwiki.annotation.Annotation;
import org.xwiki.annotation.AnnotationConfiguration;
import org.xwiki.annotation.event.AnnotationAddedEvent;
import org.xwiki.annotation.event.AnnotationDeletedEvent;
import org.xwiki.annotation.event.AnnotationUpdatedEvent;
......@@ -39,7 +40,6 @@
import org.xwiki.annotation.io.IOServiceException;
import org.xwiki.annotation.maintainer.AnnotationState;
import org.xwiki.annotation.reference.TypedStringEntityReferenceResolver;
import org.xwiki.bridge.DocumentAccessBridge;
import org.xwiki.component.annotation.Component;
import org.xwiki.component.manager.ComponentLookupException;
import org.xwiki.component.manager.ComponentManager;
......@@ -68,12 +68,6 @@
@Singleton
public class DefaultIOService implements IOService
{
/**
* The name of the field of the annotation object containing the reference of the content on which the annotation is
* added.
*/
private static final String TARGET = "target";
/**
* The execution used to get the deprecated XWikiContext.
*/
......@@ -99,12 +93,6 @@ public class DefaultIOService implements IOService
@Named("local")
private EntityReferenceSerializer<String> localSerializer;
/**
* Document access bridge used to get the annotations configuration parameters.
*/
@Inject
private DocumentAccessBridge dab;
/**
* Component manager to get the observation manager and send notifications.
*/
......@@ -117,6 +105,12 @@ public class DefaultIOService implements IOService
@Inject
private Logger logger;
/**
* The Annotation Application's configuration.
*/
@Inject
private AnnotationConfiguration configuration;
/**
* {@inheritDoc} <br />
* This implementation saves the added annotation in the document where the target of the annotation is.
......@@ -140,9 +134,8 @@ public void addAnnotation(String target, Annotation annotation) throws IOService
XWikiContext deprecatedContext = getXWikiContext();
XWikiDocument document = deprecatedContext.getWiki().getDocument(documentFullName, deprecatedContext);
// create a new object in this document to hold the annotation
String annotationClassName = getAnnotationClassName();
int id = document.createNewObject(annotationClassName, deprecatedContext);
BaseObject object = document.getObject(annotationClassName, id);
int id = document.createXObject(configuration.getAnnotationClassReference(), deprecatedContext);
BaseObject object = document.getXObject(configuration.getAnnotationClassReference(), id);
updateObject(object, annotation, deprecatedContext);
// and set additional data: author to annotation author, date to now and the annotation target
object.set(Annotation.DATE_FIELD, new Date(), deprecatedContext);
......@@ -159,9 +152,9 @@ public void addAnnotation(String target, Annotation annotation) throws IOService
// ftm don't store the type of the reference since we only need to recognize the field, not to also read it.
if (targetReference.getType() == EntityType.OBJECT_PROPERTY
|| targetReference.getType() == EntityType.DOCUMENT) {
object.set(TARGET, localSerializer.serialize(targetReference), deprecatedContext);
object.set(Annotation.TARGET_FIELD, localSerializer.serialize(targetReference), deprecatedContext);
} else {
object.set(TARGET, target, deprecatedContext);
object.set(Annotation.TARGET_FIELD, target, deprecatedContext);
}
// set the author of the document to the current user
document.setAuthor(deprecatedContext.getUser());
......@@ -206,7 +199,7 @@ public Collection<Annotation> getAnnotations(String target) throws IOServiceExce
XWikiContext deprecatedContext = getXWikiContext();
XWikiDocument document = deprecatedContext.getWiki().getDocument(docName, deprecatedContext);
// and the annotation class objects in it
List<BaseObject> objects = document.getObjects(getAnnotationClassName());
List<BaseObject> objects = document.getXObjects(configuration.getAnnotationClassReference());
// and build a list of Annotation objects
List<Annotation> result = new ArrayList<Annotation>();
if (objects == null) {
......@@ -214,7 +207,7 @@ public Collection<Annotation> getAnnotations(String target) throws IOServiceExce
}
for (BaseObject object : objects) {
// if it's not on the required target, ignore it
if (object == null || !localTargetId.equals(object.getStringValue(TARGET))) {
if (object == null || !localTargetId.equals(object.getStringValue(Annotation.TARGET_FIELD))) {
continue;
}
// use the object number as annotation id
......@@ -249,8 +242,10 @@ public Annotation getAnnotation(String target, String annotationID) throws IOSer
XWikiDocument document = deprecatedContext.getWiki().getDocument(docName, deprecatedContext);
// and the annotation class objects in it
// parse the annotation id as object index
BaseObject object = document.getObject(getAnnotationClassName(), Integer.valueOf(annotationID.toString()));
if (object == null || !localTargetId.equals(object.getStringValue(TARGET))) {
BaseObject object =
document.getXObject(configuration.getAnnotationClassReference(),
Integer.valueOf(annotationID.toString()));
if (object == null || !localTargetId.equals(object.getStringValue(Annotation.TARGET_FIELD))) {
return null;
}
// use the object number as annotation id
......@@ -296,18 +291,20 @@ public void removeAnnotation(String target, String annotationID) throws IOServic
}
// and the document object on it
BaseObject annotationObject =
document.getObject(getAnnotationClassName(), Integer.valueOf(annotationID.toString()));
document.getXObject(configuration.getAnnotationClassReference(),
Integer.valueOf(annotationID.toString()));
// if object exists and its target matches the requested target, delete it
if (annotationObject != null && localTargetId.equals(annotationObject.getStringValue(TARGET))) {
if (annotationObject != null
&& localTargetId.equals(annotationObject.getStringValue(Annotation.TARGET_FIELD))) {
document.removeObject(annotationObject);
document.setAuthor(deprecatedContext.getUser());
deprecatedContext.getWiki().saveDocument(document, "Deleted annotation " + annotationID,
deprecatedContext);
// notify listeners that an annotation was deleted
ObservationManager observationManager = componentManager.lookup(ObservationManager.class);
observationManager
.notify(new AnnotationDeletedEvent(docName, annotationID), document, deprecatedContext);
observationManager.notify(new AnnotationDeletedEvent(docName, annotationID), document,
deprecatedContext);
}
} catch (NumberFormatException e) {
throw new IOServiceException("An exception has occurred while parsing the annotation id", e);
......@@ -350,7 +347,7 @@ public void updateAnnotations(String target, Collection<Annotation> annotations)
} catch (NumberFormatException e) {
continue;
}
BaseObject object = document.getObject(getAnnotationClassName(), annId);
BaseObject object = document.getXObject(configuration.getAnnotationClassReference(), annId);
if (object == null) {
continue;
}
......@@ -402,9 +399,8 @@ protected Annotation loadAnnotationFromObject(BaseObject object, XWikiContext de
try {
annotation.set(propName, ((BaseProperty) object.get(propName)).getValue());
} catch (XWikiException e) {
this.logger.warn(
"Unable to get property " + propName + " from object " + object.getClassName() + "["
+ object.getNumber() + "]. Will not be saved in the annotation.", e);
this.logger.warn("Unable to get property " + propName + " from object " + object.getClassName()
+ "[" + object.getNumber() + "]. Will not be saved in the annotation.", e);
}
}
}
......@@ -433,8 +429,8 @@ protected boolean updateObject(BaseObject object, Annotation annotation, XWikiCo
// don't reset the state, the date (which will be set now, upon save), and ignore anything that could overwrite
// the target. Don't set the author either, will be set by caller, if needed
Collection<String> skippedFields =
Arrays
.asList(new String[] {Annotation.STATE_FIELD, Annotation.DATE_FIELD, Annotation.AUTHOR_FIELD, TARGET});
Arrays.asList(new String[] {Annotation.STATE_FIELD, Annotation.DATE_FIELD, Annotation.AUTHOR_FIELD,
Annotation.TARGET_FIELD});
// all fields in the annotation, try to put them in object (I wonder what happens if I can't...)
for (String propName : annotation.getFieldNames()) {
if (!skippedFields.contains(propName)) {
......@@ -471,15 +467,4 @@ private XWikiContext getXWikiContext()
{
return (XWikiContext) execution.getContext().getProperty("xwikicontext");
}
/**
* Helper function to return the annotation class from the annotation configuration document.
*
* @return the name of the annotation class that describes the annotation structure
*/
protected String getAnnotationClassName()
{
String configDocument = "AnnotationCode.AnnotationConfig";
return (String) dab.getProperty(configDocument, configDocument, "annotationClass");
}
}
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