/*
* 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.serializer;
import java.util.List;
import java.util.Map.Entry;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.time.DateFormatUtils;
import org.betaconceptframework.astroboa.api.model.definition.BooleanPropertyDefinition;
import org.betaconceptframework.astroboa.api.model.definition.CalendarPropertyDefinition;
import org.betaconceptframework.astroboa.api.model.definition.CmsPropertyDefinition;
import org.betaconceptframework.astroboa.api.model.definition.ComplexCmsPropertyDefinition;
import org.betaconceptframework.astroboa.api.model.definition.ContentObjectTypeDefinition;
import org.betaconceptframework.astroboa.api.model.definition.DoublePropertyDefinition;
import org.betaconceptframework.astroboa.api.model.definition.LocalizableCmsDefinition;
import org.betaconceptframework.astroboa.api.model.definition.LongPropertyDefinition;
import org.betaconceptframework.astroboa.api.model.definition.ObjectReferencePropertyDefinition;
import org.betaconceptframework.astroboa.api.model.definition.SimpleCmsPropertyDefinition;
import org.betaconceptframework.astroboa.api.model.definition.StringPropertyDefinition;
import org.betaconceptframework.astroboa.api.model.definition.TopicReferencePropertyDefinition;
import org.betaconceptframework.astroboa.api.model.io.ResourceRepresentationType;
import org.betaconceptframework.astroboa.commons.visitor.AbstractCmsPropertyDefinitionVisitor;
import org.betaconceptframework.astroboa.context.AstroboaClientContextHolder;
import org.betaconceptframework.astroboa.context.RepositoryContext;
import org.betaconceptframework.astroboa.model.impl.definition.ComplexCmsPropertyDefinitionImpl;
import org.betaconceptframework.astroboa.model.impl.definition.DoublePropertyDefinitionImpl;
import org.betaconceptframework.astroboa.model.impl.definition.LongPropertyDefinitionImpl;
import org.betaconceptframework.astroboa.util.CmsConstants;
/**
*
* Class responsible to export definition to XML or JSON
*
* Currently only JSON is supported
*
* @author Gregory Chomatas (gchomatas@betaconcept.com)
* @author Savvas Triantafyllou (striantafyllou@betaconcept.com)
*
*/
public class CmsDefinitionSerializer extends AbstractCmsPropertyDefinitionVisitor{
private MarkerSerializer serializer = null;
private LocalizableCmsDefinition rootDefinition;
public CmsDefinitionSerializer(boolean prettyPrint, boolean jsonOutput) {
serializer = new MarkerSerializer(prettyPrint, jsonOutput);
}
@Override
public void visit(ContentObjectTypeDefinition contentObjectTypeDefinition) {
rootDefinition = contentObjectTypeDefinition;
//Create start element only if output is XML
if (!serializer.outputIsJSON()){
serializer.startElement(CmsConstants.OBJECT_TYPE_ELEMENT_NAME, true, true);
}
exportDefinitionObjectAndBasicProperties(contentObjectTypeDefinition);
closeStartTagIfOutputIsXML(CmsConstants.OBJECT_TYPE_ELEMENT_NAME);
exportDisplayNameAndDescription(contentObjectTypeDefinition);
}
@Override
public void visitComplexPropertyDefinition(ComplexCmsPropertyDefinition complexPropertyDefinition) {
startTagForPropertyAndSetRootDefinitionIfNecessary(complexPropertyDefinition);
exportDefinitionObjectAndBasicProperties(complexPropertyDefinition);
closeStartTagIfOutputIsXML(CmsConstants.PROPERTY_ELEMENT_NAME);
exportDisplayNameAndDescription(complexPropertyDefinition);
}
@Override
public <T> void visitSimplePropertyDefinition(
SimpleCmsPropertyDefinition<T> simplePropertyDefinition) {
if (simplePropertyDefinition != null){
startTagForPropertyAndSetRootDefinitionIfNecessary(simplePropertyDefinition);
exportDefinitionObjectAndBasicProperties(simplePropertyDefinition);
switch (simplePropertyDefinition.getValueType()) {
case Boolean:
serializeBooleanPropertyDefinition(simplePropertyDefinition);
break;
case Date:
serializeDatePropertyDefinition(simplePropertyDefinition);
break;
case Double:
serializeDoublePropertyDefinition(simplePropertyDefinition);
break;
case Long:
serializeLongPropertyDefinition(simplePropertyDefinition);
break;
case String:
serializeStringPropertyDefinition(simplePropertyDefinition);
break;
case ObjectReference:
serializeObjectReferencePropertyDefinition(simplePropertyDefinition);
break;
case TopicReference:
serializeTopicReferenceDefinition(simplePropertyDefinition);
break;
default:
break;
}
closeStartTagIfOutputIsXML(CmsConstants.PROPERTY_ELEMENT_NAME);
exportDisplayNameAndDescription(simplePropertyDefinition);
if (rootDefinition != null && rootDefinition != simplePropertyDefinition){
serializer.endElement(CmsConstants.PROPERTY_ELEMENT_NAME, false,true);
}
}
}
private <T> void serializeTopicReferenceDefinition(
SimpleCmsPropertyDefinition<T> simplePropertyDefinition) {
if (CollectionUtils.isNotEmpty(((TopicReferencePropertyDefinition)simplePropertyDefinition).getAcceptedTaxonomies())){
serializer.writeAttribute("acceptedTaxonomies",StringUtils.join(((TopicReferencePropertyDefinition)simplePropertyDefinition).getAcceptedTaxonomies(), ","));
}
}
private <T> void serializeObjectReferencePropertyDefinition(
SimpleCmsPropertyDefinition<T> simplePropertyDefinition) {
if (CollectionUtils.isNotEmpty(((ObjectReferencePropertyDefinition)simplePropertyDefinition).getExpandedAcceptedContentTypes())){
serializer.writeAttribute("acceptedContentTypes",StringUtils.join(((ObjectReferencePropertyDefinition)simplePropertyDefinition).getExpandedAcceptedContentTypes(),","));
}
}
private <T> void serializeStringPropertyDefinition(
SimpleCmsPropertyDefinition<T> simplePropertyDefinition) {
StringPropertyDefinition stringDefinition = (StringPropertyDefinition)simplePropertyDefinition;
if (stringDefinition.isSetDefaultValue()){
serializer.writeAttribute("defaultValue",stringDefinition.getDefaultValue());
}
if (stringDefinition.getMinLength() != null){
serializer.writeAttribute("minLength",String.valueOf(stringDefinition.getMinLength()));
}
if (stringDefinition.getMaxLength() != null){
serializer.writeAttribute("maxLength",String.valueOf(stringDefinition.getMaxLength()));
}
if (stringDefinition.getPattern() != null){
serializer.writeAttribute("pattern",String.valueOf(stringDefinition.getPattern()));
}
serializer.writeAttribute("stringFormat",String.valueOf(stringDefinition.getStringFormat()));
}
private <T> void serializeLongPropertyDefinition(
SimpleCmsPropertyDefinition<T> simplePropertyDefinition) {
LongPropertyDefinition longDefinition = (LongPropertyDefinition)simplePropertyDefinition;
if (longDefinition.isSetDefaultValue()){
serializer.writeAttribute("defaultValue",String.valueOf(longDefinition.getDefaultValue()));
}
if (longDefinition.getMinValue() != null && longDefinition.getMinValue() != Long.MIN_VALUE){
serializer.writeAttribute("minValue",String.valueOf(longDefinition.getMinValue()));
serializer.writeAttribute("minValueIsExclusive",String.valueOf(((LongPropertyDefinitionImpl)longDefinition).isMinValueExclusive()));
}
if (longDefinition.getMaxValue() != null && longDefinition.getMaxValue() != Long.MAX_VALUE){
serializer.writeAttribute("maxValue",String.valueOf(longDefinition.getMaxValue()));
serializer.writeAttribute("maxValueIsExclusive",String.valueOf(((LongPropertyDefinitionImpl)longDefinition).isMaxValueExclusive()));
}
}
private <T> void serializeDoublePropertyDefinition(
SimpleCmsPropertyDefinition<T> simplePropertyDefinition) {
DoublePropertyDefinition doubleDefinition = (DoublePropertyDefinition)simplePropertyDefinition;
if (doubleDefinition.isSetDefaultValue()){
serializer.writeAttribute("defaultValue", String.valueOf(doubleDefinition.getDefaultValue()));
}
if (doubleDefinition.getMinValue() != null && doubleDefinition.getMinValue() != Double.MIN_VALUE){
serializer.writeAttribute("minValue",String.valueOf(doubleDefinition.getMinValue()));
serializer.writeAttribute("minValueIsExclusive",String.valueOf(((DoublePropertyDefinitionImpl)doubleDefinition).isMinValueExclusive()));
}
if (doubleDefinition.getMaxValue() != null && doubleDefinition.getMinValue() != Double.MAX_VALUE){
serializer.writeAttribute("maxValue",String.valueOf(doubleDefinition.getMaxValue()));
serializer.writeAttribute("maxValueIsExclusive",String.valueOf(((DoublePropertyDefinitionImpl)doubleDefinition).isMaxValueExclusive()));
}
}
private <T> void serializeDatePropertyDefinition(
SimpleCmsPropertyDefinition<T> simplePropertyDefinition) {
CalendarPropertyDefinition calendarDefinition = (CalendarPropertyDefinition)simplePropertyDefinition;
serializer.writeAttribute("pattern",calendarDefinition.getPattern());
if (calendarDefinition.isSetDefaultValue()){
serializer.writeAttribute("defaultValue", DateFormatUtils.format(calendarDefinition.getDefaultValue().getTimeInMillis(), calendarDefinition.getPattern()));
}
}
private <T> void serializeBooleanPropertyDefinition(
SimpleCmsPropertyDefinition<T> simplePropertyDefinition) {
BooleanPropertyDefinition booleanDefinition = (BooleanPropertyDefinition)simplePropertyDefinition;
if (booleanDefinition.isSetDefaultValue()){
serializer.writeAttribute("defaultValue", String.valueOf(booleanDefinition.getDefaultValue()));
}
}
@Override
public void finishedChildDefinitionsVisit(LocalizableCmsDefinition parentDefinition) {
super.finishedChildDefinitionsVisit(parentDefinition);
if (serializer.outputIsJSON()){
serializer.endArray(CmsConstants.PROPERTY_ELEMENT_NAME);
}
serializer.endElement(CmsConstants.ARRAY_OF_PROPERTIES_ELEMENT_NAME, false, true);
if (rootDefinition != null && rootDefinition != parentDefinition){
serializer.endElement(CmsConstants.PROPERTY_ELEMENT_NAME, false, true);
}
}
@Override
public void startChildDefinitionsVisit(
LocalizableCmsDefinition parentDefinition) {
super.startChildDefinitionsVisit(parentDefinition);
serializer.startElement(CmsConstants.ARRAY_OF_PROPERTIES_ELEMENT_NAME, false, true);
if (serializer.outputIsJSON()){
serializer.startArray(CmsConstants.PROPERTY_ELEMENT_NAME);
}
}
public String exportOutcome() {
//Create an end tag only if output is XML
if (rootDefinition != null && ! serializer.outputIsJSON()){
if (rootDefinition instanceof ContentObjectTypeDefinition){
serializer.endElement(CmsConstants.OBJECT_TYPE_ELEMENT_NAME, false,true);
}
else if (rootDefinition instanceof CmsPropertyDefinition ){
serializer.endElement(CmsConstants.PROPERTY_ELEMENT_NAME, false,true);
}
}
return serializer.serialize();
}
private void exportDefinitionObjectAndBasicProperties(LocalizableCmsDefinition cmsDefinition) {
//Name
exportName(cmsDefinition);
//Path
exportPath(cmsDefinition);
//Value Type
exportValueType(cmsDefinition);
//Url
exportUrl(cmsDefinition);
//Schema URL
exportSchemaUrl(cmsDefinition);
if (cmsDefinition instanceof CmsPropertyDefinition){
//Cardinality
exportCardinality((CmsPropertyDefinition)cmsDefinition);
}
}
private void exportCardinality(CmsPropertyDefinition cmsDefinition) {
serializer.writeAttribute("mandatory",String.valueOf(((CmsPropertyDefinition)cmsDefinition).isMandatory()));
serializer.writeAttribute("multiple",String.valueOf(((CmsPropertyDefinition)cmsDefinition).isMultiple()));
}
private void exportUrl(LocalizableCmsDefinition cmsDefinition) {
serializer.writeAttribute("url",cmsDefinition.url(serializer.outputIsJSON()? ResourceRepresentationType.JSON : ResourceRepresentationType.XML));
}
private void exportSchemaUrl(LocalizableCmsDefinition cmsDefinition) {
serializer.writeAttribute("schemaUrl",cmsDefinition.url(ResourceRepresentationType.XSD));
}
private void exportDisplayNameAndDescription(LocalizableCmsDefinition cmsDefinition) {
if (cmsDefinition.getDisplayName() != null && cmsDefinition.getDisplayName().hasLocalizedLabels()){
if (serializer.outputIsJSON()){
serializer.startElement("label",true,true);
for (Entry<String,String> localizedLabel : cmsDefinition.getDisplayName().getLocalizedLabels().entrySet()){
serializer.writeAttribute(localizedLabel.getKey(),localizedLabel.getValue());
}
serializer.endElement("label",true,true);
}
else{
for (Entry<String,String> localizedLabel : cmsDefinition.getDisplayName().getLocalizedLabels().entrySet()){
serializer.startElement("label",true,true);
serializer.writeAttribute(CmsConstants.LANG_ATTRIBUTE_NAME_WITH_PREFIX, localizedLabel.getKey());
serializer.endElement("label",true,false);
serializer.writeContent(localizedLabel.getValue(), true);
serializer.endElement("label",false,true);
}
}
}
if (cmsDefinition.getDescription() != null && cmsDefinition.getDescription().hasLocalizedLabels()){
if (serializer.outputIsJSON()){
serializer.startElement("description",true,true);
for (Entry<String,String> localizedLabel : cmsDefinition.getDescription().getLocalizedLabels().entrySet()){
serializer.writeAttribute(localizedLabel.getKey(),localizedLabel.getValue());
}
serializer.endElement("description",true,true);
}
else{
for (Entry<String,String> localizedLabel : cmsDefinition.getDescription().getLocalizedLabels().entrySet()){
serializer.startElement("description",true,true);
serializer.writeAttribute(CmsConstants.LANG_ATTRIBUTE_NAME_WITH_PREFIX, localizedLabel.getKey());
serializer.endElement("description",true,false);
serializer.writeContent(localizedLabel.getValue(), true);
serializer.endElement("description",false,true);
}
}
}
}
private void exportValueType(LocalizableCmsDefinition cmsDefinition) {
if (cmsDefinition instanceof ComplexCmsPropertyDefinition &&
StringUtils.isNotBlank(((ComplexCmsPropertyDefinitionImpl)cmsDefinition).getTypeName())){
serializer.writeAttribute("valueType",((ComplexCmsPropertyDefinitionImpl)cmsDefinition).getTypeName());
}
else if (cmsDefinition instanceof ContentObjectTypeDefinition &&
CollectionUtils.isNotEmpty(((ContentObjectTypeDefinition)cmsDefinition).getSuperContentTypes())) {
//Object type is always the last element of the list
List<String> objectTypes = ((ContentObjectTypeDefinition)cmsDefinition).getSuperContentTypes();
serializer.writeAttribute("valueType",objectTypes.get(objectTypes.size()-1));
}
else{
serializer.writeAttribute("valueType",cmsDefinition.getValueType().toString());
}
}
private void exportName(LocalizableCmsDefinition cmsDefinition) {
serializer.writeAttribute("name",cmsDefinition.getName());
}
private void exportPath(LocalizableCmsDefinition cmsDefinition) {
if (cmsDefinition instanceof CmsPropertyDefinition){
serializer.writeAttribute("path",((CmsPropertyDefinition)cmsDefinition).getPath());
}
else{
serializer.writeAttribute("path",cmsDefinition.getName());
}
}
public String getServerURL() {
RepositoryContext repositoryContext = AstroboaClientContextHolder.getRepositoryContextForActiveClient();
if (repositoryContext != null && repositoryContext.getCmsRepository() != null &&
StringUtils.isNotBlank(repositoryContext.getCmsRepository().getServerURL())){
String serverURL = repositoryContext.getCmsRepository().getServerURL().trim();
return serverURL.endsWith("/")? serverURL.substring(0, serverURL.length()-1) : serverURL;
}
return null;
}
public String getRestfulApiBasePath() {
RepositoryContext repositoryContext = AstroboaClientContextHolder.getRepositoryContextForActiveClient();
if (
repositoryContext != null &&
repositoryContext.getCmsRepository() != null &&
StringUtils.isNotBlank(repositoryContext.getCmsRepository().getRestfulApiBasePath())) {
String restfulApiBasePath = repositoryContext.getCmsRepository().getRestfulApiBasePath().trim();
if (!restfulApiBasePath.startsWith("/")) {
restfulApiBasePath = "/" + restfulApiBasePath;
}
return restfulApiBasePath.endsWith("/")? restfulApiBasePath.substring(0, restfulApiBasePath.length()-1) : restfulApiBasePath;
}
return null;
}
private void closeStartTagIfOutputIsXML(String elementName){
if (!serializer.outputIsJSON()){
serializer.endElement(elementName, true, false);
}
}
private void startTagForPropertyAndSetRootDefinitionIfNecessary(CmsPropertyDefinition cmsPropertyDefinition){
if (rootDefinition == null){
rootDefinition = cmsPropertyDefinition;
//Create start element only if output is XML
if (!serializer.outputIsJSON()){
serializer.startElement(CmsConstants.PROPERTY_ELEMENT_NAME, true, true);
}
}
else{
serializer.startElement(CmsConstants.PROPERTY_ELEMENT_NAME, true, ! serializer.outputIsJSON());
}
}
private class MarkerSerializer extends AbstractSerializer {
public MarkerSerializer(boolean prettyPrint, boolean jsonOutput) {
super(prettyPrint, jsonOutput);
}
}
}