/*
* 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.internal.filter;
import java.io.IOException;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
import org.xwiki.component.annotation.Component;
import org.xwiki.component.manager.ComponentLookupException;
import org.xwiki.component.manager.ComponentManager;
import org.xwiki.component.util.DefaultParameterizedType;
import org.xwiki.filter.FilterEventParameters;
import org.xwiki.filter.FilterException;
import org.xwiki.filter.event.model.WikiDocumentFilter;
import org.xwiki.filter.input.BeanInputFilterStream;
import org.xwiki.filter.input.BeanInputFilterStreamFactory;
import org.xwiki.filter.input.InputFilterStreamFactory;
import org.xwiki.filter.input.InputSource;
import org.xwiki.filter.instance.input.BeanEntityEventGenerator;
import org.xwiki.filter.instance.input.DocumentInstanceInputProperties;
import org.xwiki.filter.instance.input.EntityEventGenerator;
import org.xwiki.filter.instance.output.DocumentInstanceOutputProperties;
import org.xwiki.filter.output.BeanOutputFilterStream;
import org.xwiki.filter.output.BeanOutputFilterStreamFactory;
import org.xwiki.filter.output.OutputFilterStreamFactory;
import org.xwiki.filter.output.OutputTarget;
import org.xwiki.filter.output.StringWriterOutputTarget;
import org.xwiki.filter.output.WriterOutputTarget;
import org.xwiki.filter.xar.input.XARInputProperties;
import org.xwiki.filter.xar.input.XARInputProperties.SourceType;
import org.xwiki.filter.xar.internal.XARFilter;
import org.xwiki.filter.xar.internal.XARFilterUtils;
import org.xwiki.filter.xar.output.XAROutputProperties;
import org.xwiki.model.reference.DocumentReference;
import org.xwiki.model.reference.EntityReference;
import org.xwiki.model.reference.SpaceReference;
import com.xpn.xwiki.doc.XWikiAttachment;
import com.xpn.xwiki.doc.XWikiDocument;
import com.xpn.xwiki.internal.filter.output.EntityOutputFilterStream;
import com.xpn.xwiki.internal.filter.output.XWikiDocumentOutputFilterStream;
import com.xpn.xwiki.objects.BaseObject;
import com.xpn.xwiki.objects.BaseProperty;
import com.xpn.xwiki.objects.classes.BaseClass;
import com.xpn.xwiki.objects.classes.PropertyClass;
/**
* Various XWikiDocument related helpers.
*
* @version $Id: 5c8d36abfe47ab07100313bee9c633191807a52a $
* @since 9.0RC1
*/
@Component(roles = XWikiDocumentFilterUtils.class)
@Singleton
public class XWikiDocumentFilterUtils
{
@Inject
@Named(XARFilterUtils.ROLEHINT_CURRENT)
private InputFilterStreamFactory xarInputFilterStreamFactory;
@Inject
@Named(XARFilterUtils.ROLEHINT_CURRENT)
private OutputFilterStreamFactory xarOutputFilterStreamFactory;
@Inject
private ComponentManager componentManager;
// Import
private <T> Class<T> getClass(Object entity)
{
Class<T> entityClass;
if (entity instanceof Class) {
entityClass = (Class<T>) entity;
} else if (entity instanceof XWikiDocument) {
entityClass = (Class<T>) XWikiDocument.class;
} else if (entity instanceof XWikiAttachment) {
entityClass = (Class<T>) XWikiAttachment.class;
} else if (entity instanceof BaseClass) {
entityClass = (Class<T>) BaseClass.class;
} else if (entity instanceof BaseObject) {
entityClass = (Class<T>) BaseObject.class;
} else if (entity instanceof BaseProperty) {
entityClass = (Class<T>) BaseProperty.class;
} else if (entity instanceof PropertyClass) {
entityClass = (Class<T>) PropertyClass.class;
} else {
entityClass = (Class<T>) entity.getClass();
}
return entityClass;
}
private SourceType getSourceType(Class<?> entityClass) throws FilterException
{
SourceType sourceType;
if (entityClass == XWikiDocument.class) {
sourceType = SourceType.DOCUMENT;
} else if (entityClass == XWikiAttachment.class) {
sourceType = SourceType.ATTACHMENT;
} else if (entityClass == BaseClass.class) {
sourceType = SourceType.CLASS;
} else if (entityClass == BaseObject.class) {
sourceType = SourceType.OBJECT;
} else if (entityClass == BaseProperty.class) {
sourceType = SourceType.OBJECTPROPERTY;
} else if (entityClass == PropertyClass.class) {
sourceType = SourceType.CLASSPROPERTY;
} else {
throw new FilterException("Unsupported type [" + entityClass + "]");
}
return sourceType;
}
/**
* @param entity the entity to write to or its class to create a new one
* @param source the stream to read
* @return the imported entity, same as {@code entity} if not null
* @throws FilterException when failing to import
* @throws IOException when failing to import
* @throws ComponentLookupException when failing to find a EntityOutputFilterStream corresponding to passed class
*/
public <T> T importEntity(Object entity, InputSource source)
throws FilterException, IOException, ComponentLookupException
{
// Output
DocumentInstanceOutputProperties documentProperties = new DocumentInstanceOutputProperties();
// Input
XARInputProperties xarProperties = new XARInputProperties();
return importEntity(getClass(entity), entity instanceof Class ? null : (T) entity, source, xarProperties,
documentProperties);
}
/**
* @param entityClass to class used to find the {@link EntityOutputFilterStream} component
* @param entity the entity to write to or null to create a new entity of the passed class
* @param source the stream to read
* @param xarProperties the configuration of the input filter
* @param documentProperties the configuration of the output filter
* @return the imported entity, same as {@code entity} if not null
* @throws FilterException when failing to import
* @throws IOException when failing to import
* @throws ComponentLookupException when failing to find a EntityOutputFilterStream corresponding to passed class
*/
public <T> T importEntity(Class<T> entityClass, T entity, InputSource source, XARInputProperties xarProperties,
DocumentInstanceOutputProperties documentProperties)
throws FilterException, IOException, ComponentLookupException
{
// Output
EntityOutputFilterStream<T> filterStream = this.componentManager
.getInstance(new DefaultParameterizedType(null, EntityOutputFilterStream.class, entityClass));
filterStream.setProperties(documentProperties);
filterStream.setEntity(entity);
if (filterStream instanceof XWikiDocumentOutputFilterStream) {
((XWikiDocumentOutputFilterStream) filterStream).disableRenderingEvents();
}
// Input
xarProperties.setSourceType(getSourceType(entityClass));
xarProperties.setSource(source);
BeanInputFilterStream<XARInputProperties> xarReader =
((BeanInputFilterStreamFactory<XARInputProperties>) this.xarInputFilterStreamFactory)
.createInputFilterStream(xarProperties);
// Convert
xarReader.read(filterStream.getFilter());
xarReader.close();
return filterStream.getEntity();
}
/**
* @param source the stream to read
* @param xarProperties the configuration of the input filter
* @param documentProperties the configuration of the output filter
* @return the imported document
* @throws FilterException when failing to import
* @throws IOException when failing to import
* @throws ComponentLookupException when failing to find a EntityOutputFilterStream corresponding to passed class
*/
public XWikiDocument importDocument(InputSource source, XARInputProperties xarProperties,
DocumentInstanceOutputProperties documentProperties)
throws FilterException, IOException, ComponentLookupException
{
return importEntity(XWikiDocument.class, null, source, xarProperties, documentProperties);
}
// Export
/**
* @param entity the entity to read
* @return the XML as a String
* @throws ComponentLookupException failed to find an event generator for passed entity
* @throws FilterException when failing to generate export the passed entity
* @throws IOException when failing to close the stream
*/
public String exportEntity(Object entity) throws ComponentLookupException, FilterException, IOException
{
return exportEntity(entity, new XAROutputProperties());
}
/**
* @param entity the entity to read
* @param xarProperties the configuration of the output filter
* @return the XML as a String
* @throws ComponentLookupException failed to find an event generator for passed entity
* @throws FilterException when failing to generate export the passed entity
* @throws IOException when failing to close the stream
*/
public String exportEntity(Object entity, XAROutputProperties xarProperties)
throws ComponentLookupException, FilterException, IOException
{
return exportEntity(entity, xarProperties, new DocumentInstanceInputProperties());
}
/**
* @param entity the entity to read
* @param target the target where to write the result
* @throws ComponentLookupException failed to find an event generator for passed entity
* @throws FilterException when failing to generate export the passed entity
* @throws IOException when failing to close the stream
*/
public void exportEntity(Object entity, OutputTarget target)
throws ComponentLookupException, FilterException, IOException
{
exportEntity(entity, target, new DocumentInstanceInputProperties());
}
/**
* @param entity the entity to read
* @param target the target where to write the result
* @param documentProperties the configuration of the input filter
* @throws ComponentLookupException failed to find an event generator for passed entity
* @throws FilterException when failing to generate export the passed entity
* @throws IOException when failing to close the stream
*/
public void exportEntity(Object entity, OutputTarget target, DocumentInstanceInputProperties documentProperties)
throws ComponentLookupException, FilterException, IOException
{
exportEntity(entity, target, new XAROutputProperties(), documentProperties);
}
/**
* @param entity the entity to read
* @param xarProperties the configuration of the output filter
* @param documentProperties the configuration of the input filter
* @return the XML as a String
* @throws ComponentLookupException failed to find an event generator for passed entity
* @throws FilterException when failing to generate export the passed entity
* @throws IOException when failing to close the stream
*/
public String exportEntity(Object entity, XAROutputProperties xarProperties,
DocumentInstanceInputProperties documentProperties)
throws ComponentLookupException, FilterException, IOException
{
WriterOutputTarget target = new StringWriterOutputTarget();
exportEntity(entity, target, xarProperties, documentProperties);
return target.toString();
}
/**
* @param entity the entity to read
* @param target the target where to write the result
* @param xarProperties the configuration of the output filter
* @param documentProperties the configuration of the input filter
* @throws ComponentLookupException failed to find an event generator for passed entity
* @throws FilterException when failing to generate export the passed entity
* @throws IOException when failing to close the stream
*/
public void exportEntity(Object entity, OutputTarget target, XAROutputProperties xarProperties,
DocumentInstanceInputProperties documentProperties)
throws ComponentLookupException, FilterException, IOException
{
// Input
documentProperties.setVerbose(false);
// Output
xarProperties.setForceDocument(true);
if (target != null) {
xarProperties.setTarget(target);
}
xarProperties.setVerbose(false);
BeanOutputFilterStream<XAROutputProperties> xarFilter =
((BeanOutputFilterStreamFactory<XAROutputProperties>) this.xarOutputFilterStreamFactory)
.createOutputFilterStream(xarProperties);
XARFilter filter = (XARFilter) xarFilter.getFilter();
BeanEntityEventGenerator<Object, DocumentInstanceInputProperties> generator = this.componentManager
.getInstance(new DefaultParameterizedType(null, EntityEventGenerator.class, getClass(entity)));
// Spaces and document events
FilterEventParameters documentParameters = null;
DocumentReference documentReference = null;
if (entity instanceof XWikiDocument) {
documentReference = ((XWikiDocument) entity).getDocumentReference();
for (SpaceReference spaceReference : documentReference.getSpaceReferences()) {
filter.beginWikiSpace(spaceReference.getName(), FilterEventParameters.EMPTY);
}
documentParameters = new FilterEventParameters();
documentParameters.put(WikiDocumentFilter.PARAMETER_LOCALE, ((XWikiDocument) entity).getDefaultLocale());
filter.beginWikiDocument(documentReference.getName(), documentParameters);
}
// Document Locale events
generator.write(entity, xarFilter, documentProperties);
// Document and spaces events
if (documentParameters != null) {
filter.endWikiDocument(documentReference.getName(), documentParameters);
documentReference = ((XWikiDocument) entity).getDocumentReference();
for (EntityReference reference =
documentReference.getParent(); reference instanceof SpaceReference; reference = reference.getParent()) {
filter.beginWikiSpace(reference.getName(), FilterEventParameters.EMPTY);
}
}
xarFilter.close();
}
}