/*
* Copyright (C) 2005-2012 BetaCONCEPT Limited
*
* This file is part of Astroboa.
*
* Astroboa 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 3 of the License, or
* (at your option) any later version.
*
* Astroboa 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 Astroboa. If not, see <http://www.gnu.org/licenses/>.
*/
package org.betaconceptframework.astroboa.model.jaxb;
import java.io.IOException;
import java.io.StringWriter;
import java.io.Writer;
import java.util.Arrays;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.stream.XMLStreamWriter;
import org.apache.commons.lang.ArrayUtils;
import org.betaconceptframework.astroboa.api.model.BetaConceptNamespaceConstants;
import org.betaconceptframework.astroboa.api.model.CmsRepositoryEntity;
import org.betaconceptframework.astroboa.api.model.ContentObject;
import org.betaconceptframework.astroboa.api.model.RepositoryUser;
import org.betaconceptframework.astroboa.api.model.Space;
import org.betaconceptframework.astroboa.api.model.Taxonomy;
import org.betaconceptframework.astroboa.api.model.Topic;
import org.betaconceptframework.astroboa.api.model.definition.CmsDefinition;
import org.betaconceptframework.astroboa.api.model.definition.CmsPropertyDefinition;
import org.betaconceptframework.astroboa.api.model.exception.CmsException;
import org.betaconceptframework.astroboa.api.model.io.ResourceRepresentationType;
import org.betaconceptframework.astroboa.api.model.visitor.DefinitionVisitor.VisitType;
import org.betaconceptframework.astroboa.context.AstroboaClientContextHolder;
import org.betaconceptframework.astroboa.model.jaxb.adapter.ContentObjectAdapter;
import org.betaconceptframework.astroboa.model.jaxb.adapter.LocalizationAdapter;
import org.betaconceptframework.astroboa.model.jaxb.listener.AstroboaMarshalListener;
import org.betaconceptframework.astroboa.model.jaxb.type.ContentObjectType;
import org.betaconceptframework.astroboa.model.jaxb.writer.JSONXmlStreamWriter;
import org.betaconceptframework.astroboa.model.lazy.LazyLoader;
import org.betaconceptframework.astroboa.serializer.CmsDefinitionSerializer;
import org.betaconceptframework.astroboa.util.SchemaUtils;
import org.codehaus.jackson.JsonFactory;
import org.codehaus.jackson.JsonGenerator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Entry point for exporting a {@link CmsRepositoryEntity} to Xml or Json.
*
* <p>
* Exporting a {@link CmsRepositoryEntity} to xml or JSON
* is done through methods {@link #toXml(CmsRepositoryEntity)},
* {@link #toJson(CmsRepositoryEntity)} for full exporting and
* methods {@link #toXml(CmsRepositoryEntity, String...)} and
* {@link #toJson(CmsRepositoryEntity, String...)} for partial exporting,
* i.e. only specified properties will be exported.
* </p>
*
* <p>
* However it is recommended to use method {@link CmsRepositoryEntity#xml()}
* or {@link CmsRepositoryEntity#json()} instead.
* </p>
*
* @author Gregory Chomatas (gchomatas@betaconcept.com)
* @author Savvas Triantafyllou (striantafyllou@betaconcept.com)
*
*/
public enum CmsEntitySerialization {
Context;
private static final JAXBContext jaxbContext = initContext();
public final Logger logger = LoggerFactory.getLogger(getClass());
private JsonFactory jsonFactory = new JsonFactory();
private static JAXBContext initContext() {
try {
return JAXBContext.newInstance("org.betaconceptframework.astroboa.model.impl");
} catch (JAXBException e) {
e.printStackTrace();
return null;
}
}
public Marshaller createMarshaller(ResourceRepresentationType<?> resourceRepresentationType, boolean prettyPrint) throws JAXBException{
boolean jsonResourceRepresentationType = resourceRepresentationType!=null&&ResourceRepresentationType.JSON.equals(resourceRepresentationType);
Marshaller marshaller = jaxbContext.createMarshaller();
marshaller.setListener(new AstroboaMarshalListener(jsonResourceRepresentationType));
if (jsonResourceRepresentationType){
LocalizationAdapter localizationAdapter = new LocalizationAdapter();
localizationAdapter.useJsonVersion();
marshaller.setAdapter(localizationAdapter);
}
marshaller.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, prettyPrint);
return new AstroboaMarshaller(marshaller, resourceRepresentationType);
}
public String toJson(CmsRepositoryEntity cmsRepositoryEntity,boolean exportBinaryContent,boolean prettyPrint,String... propertyPathsToBeMarshalled){
return marshalEntity(cmsRepositoryEntity, ResourceRepresentationType.JSON, exportBinaryContent, prettyPrint, propertyPathsToBeMarshalled);
}
public String toXml(CmsRepositoryEntity cmsRepositoryEntity,boolean exportBinaryContent ,boolean prettyPrint, String... propertyPathsToBeMarshalled){
return marshalEntity(cmsRepositoryEntity, ResourceRepresentationType.XML, exportBinaryContent, prettyPrint, propertyPathsToBeMarshalled);
}
private String marshalEntity(CmsRepositoryEntity cmsRepositoryEntity, ResourceRepresentationType<?> resourceRepresentationType,
boolean exportBinaryContent, boolean prettyPrint, String... propertyPathsToBeMarshalled){
if (cmsRepositoryEntity != null){
if (cmsRepositoryEntity instanceof ContentObject ||
cmsRepositoryEntity instanceof Topic ||
cmsRepositoryEntity instanceof Space ||
cmsRepositoryEntity instanceof RepositoryUser ||
cmsRepositoryEntity instanceof Taxonomy ){
StringWriter writer = new StringWriter();
Marshaller marshaller = null;
try {
marshaller = createMarshaller(resourceRepresentationType, prettyPrint);
if (cmsRepositoryEntity instanceof ContentObject){
if (! ArrayUtils.isEmpty(propertyPathsToBeMarshalled)){
marshaller.setProperty(AstroboaMarshaller.CMS_PROPERTIES_TO_BE_MARSHALLED, Arrays.asList(propertyPathsToBeMarshalled));
}
//ContentObject needs special marshaling as JAXB does not have
//enough information in order to initialize appropriate adapter for
//ContentObject
ContentObjectAdapter adapter = new ContentObjectAdapter();
adapter.setMarshaller(marshaller, exportBinaryContent,ArrayUtils.isEmpty(propertyPathsToBeMarshalled));
marshaller.setAdapter(adapter);
ContentObjectType contentObjectType =
marshaller.getAdapter(ContentObjectAdapter.class).marshal((ContentObject) cmsRepositoryEntity);
JAXBElement<ContentObjectType> contentObjectTypeJaxb =
new JAXBElement<ContentObjectType>(((ContentObject) cmsRepositoryEntity).getTypeDefinition().getQualifiedName(),
ContentObjectType.class, null, contentObjectType);
marshaller.marshal(contentObjectTypeJaxb, writer);
}
else{
//Provide schema location
marshaller.setProperty(Marshaller.JAXB_SCHEMA_LOCATION,
" "+BetaConceptNamespaceConstants.ASTROBOA_MODEL_DEFINITION_URI+" "+
SchemaUtils.buildSchemaLocationForAstroboaModelSchemaAccordingToActiveClient());
marshaller.marshal(cmsRepositoryEntity, writer);
}
} catch (Exception e) {
throw new CmsException(e);
}
finally{
marshaller = null;
}
return writer.toString();
}
else{
throw new CmsException("Creating XML for entity type "+ cmsRepositoryEntity.getClass().getName() + " is not supported");
}
}
throw new CmsException("No entity is provided. Unable to create xml");
}
public XMLStreamWriter createJsonXmlStreamWriter(Writer writer, boolean stripRoot, boolean prettyPrint) throws IOException{
final JsonGenerator jsonGenerator = createJsonGenerator(writer, prettyPrint);
return new JSONXmlStreamWriter(jsonGenerator, stripRoot);
}
public JsonGenerator createJsonGenerator(Writer writer, boolean prettyPrint)
throws IOException {
final JsonGenerator jsonGenerator = jsonFactory.createJsonGenerator(writer);
if (prettyPrint){
jsonGenerator.useDefaultPrettyPrinter();
}
return jsonGenerator;
}
public String toJson(CmsDefinition cmsDefinition, boolean prettyPrint) {
return marshalDefinition(cmsDefinition, ResourceRepresentationType.JSON, prettyPrint);
}
public String toXml(CmsDefinition cmsDefinition, boolean prettyPrint) {
return marshalDefinition(cmsDefinition, ResourceRepresentationType.XML,prettyPrint);
}
private String marshalDefinition(CmsDefinition cmsDefinition, ResourceRepresentationType<?> resourceRepresentationType,boolean prettyPrint){
if (cmsDefinition != null){
CmsDefinitionSerializer cmsDefinitionExportVisitor = new CmsDefinitionSerializer(prettyPrint,ResourceRepresentationType.JSON.equals(resourceRepresentationType));
cmsDefinitionExportVisitor.setVisitType(VisitType.Full);
cmsDefinition.accept(cmsDefinitionExportVisitor);
return cmsDefinitionExportVisitor.exportOutcome();
}
else{
throw new CmsException("Definition is null. Cannot serialize to "+resourceRepresentationType);
}
}
public String toXsd(CmsDefinition cmsDefinition) {
LazyLoader lazyLoader = AstroboaClientContextHolder.getLazyLoaderForActiveClient();
if (lazyLoader != null){
String fullPropertyDefinitionPath = cmsDefinition.getName();
if (cmsDefinition instanceof CmsPropertyDefinition){
fullPropertyDefinitionPath = ((CmsPropertyDefinition)cmsDefinition).getFullPath();
}
return lazyLoader.getDefinitionService().getCmsDefinition(fullPropertyDefinitionPath, ResourceRepresentationType.XSD,true);
}
return null;
}
}