Java tutorial
/* * 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.adapter; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Map; import javax.xml.bind.JAXBElement; import javax.xml.bind.JAXBException; import javax.xml.bind.Marshaller; import javax.xml.bind.PropertyException; import javax.xml.bind.Unmarshaller; import javax.xml.bind.annotation.adapters.XmlAdapter; import javax.xml.datatype.DatatypeFactory; import javax.xml.namespace.QName; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.MapUtils; import org.apache.commons.lang.StringUtils; import org.betaconceptframework.astroboa.api.model.BinaryChannel; import org.betaconceptframework.astroboa.api.model.BinaryProperty; import org.betaconceptframework.astroboa.api.model.BooleanProperty; import org.betaconceptframework.astroboa.api.model.CalendarProperty; import org.betaconceptframework.astroboa.api.model.CmsProperty; import org.betaconceptframework.astroboa.api.model.ComplexCmsProperty; import org.betaconceptframework.astroboa.api.model.ComplexCmsRootProperty; import org.betaconceptframework.astroboa.api.model.ContentObject; import org.betaconceptframework.astroboa.api.model.DoubleProperty; import org.betaconceptframework.astroboa.api.model.LongProperty; import org.betaconceptframework.astroboa.api.model.ObjectReferenceProperty; import org.betaconceptframework.astroboa.api.model.SimpleCmsProperty; import org.betaconceptframework.astroboa.api.model.StringProperty; import org.betaconceptframework.astroboa.api.model.Topic; import org.betaconceptframework.astroboa.api.model.TopicReferenceProperty; import org.betaconceptframework.astroboa.api.model.ValueType; 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.SimpleCmsPropertyDefinition; import org.betaconceptframework.astroboa.api.model.exception.CmsException; import org.betaconceptframework.astroboa.api.model.io.ResourceRepresentationType; import org.betaconceptframework.astroboa.context.AstroboaClientContextHolder; import org.betaconceptframework.astroboa.model.impl.ComplexCmsPropertyImpl; import org.betaconceptframework.astroboa.model.jaxb.AstroboaValidationEventHandler; import org.betaconceptframework.astroboa.model.jaxb.type.BinaryChannelType; import org.betaconceptframework.astroboa.model.jaxb.type.CmsPropertyType; import org.betaconceptframework.astroboa.model.jaxb.type.ComplexCmsPropertyType; import org.betaconceptframework.astroboa.model.jaxb.type.ContentObjectType; import org.betaconceptframework.astroboa.model.jaxb.type.SimpleCmsPropertyType; import org.betaconceptframework.astroboa.model.jaxb.type.TopicType; import org.betaconceptframework.astroboa.model.jaxb.visitor.ContentObjectMarshalVisitor; import org.betaconceptframework.astroboa.model.lazy.LazyLoader; import org.betaconceptframework.astroboa.util.SchemaUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Class responsible to marshal a content object * * @author Gregory Chomatas (gchomatas@betaconcept.com) * @author Savvas Triantafyllou (striantafyllou@betaconcept.com) * */ public class ContentObjectAdapter extends XmlAdapter<ContentObjectType, ContentObject> { private final Logger logger = LoggerFactory.getLogger(getClass()); //Used for unmarshaling. //Does not follow the specs but there is no other //way for JAXB to decide which JAXBElement to create for cms properties //since ObjectFactory does not contain any creation method for these cms properties private Unmarshaller unmarshaller; private DatatypeFactory df; private Marshaller marshaller; private ContentObjectMarshalVisitor marshallerVisitor; private boolean serializeBinaryContent; private boolean exportAllProperties; @Override public ContentObjectType marshal(ContentObject contentObject) throws Exception { String contentObjectTypeName = retrieveContentObjectType(contentObject); ContentObjectTypeDefinition contentObjectTypeDefinition = contentObject.getTypeDefinition(); if (contentObjectTypeDefinition == null) { throw new CmsException("Unable to locate definition for content object " + contentObject.getId() + " with type " + contentObjectTypeName); } JAXBElement<ContentObjectType> contentObjectTypeJaxb = new JAXBElement<ContentObjectType>( contentObjectTypeDefinition.getQualifiedName(), ContentObjectType.class, null, new ContentObjectType()); ContentObjectType contentObjectType = contentObjectTypeJaxb.getValue(); if (marshallerVisitor == null) { marshallerVisitor = new ContentObjectMarshalVisitor(); } marshallerVisitor.initialize(contentObject, contentObjectType, marshaller, serializeBinaryContent, exportAllProperties); //Marshal object properties defined by its content type contentObjectTypeDefinition.accept(marshallerVisitor); //Marshal object's aspects if (CollectionUtils.isNotEmpty(contentObject.getComplexCmsRootProperty().getAspects())) { marshallerVisitor.enableAspectDefinitionVisit(); Collection<ComplexCmsPropertyDefinition> aspectDefinitions = contentObject.getComplexCmsRootProperty() .getAspectDefinitions().values(); for (ComplexCmsPropertyDefinition aspectDefinition : aspectDefinitions) { aspectDefinition.accept(marshallerVisitor); } } // Check if one or more aspects have been removed. // If this is the case then a null value for them must be marshalled List<String> pathsOfPropertiesMarkedForRemoval = ((ComplexCmsPropertyImpl) contentObject .getComplexCmsRootProperty()).getPathsOfPropertiesMarkedForRemoval(); if (pathsOfPropertiesMarkedForRemoval != null && !pathsOfPropertiesMarkedForRemoval.isEmpty()) { LazyLoader lazyLoader = AstroboaClientContextHolder.getLazyLoaderForActiveClient(); for (String pathOfPropertyMarkedForRemoval : pathsOfPropertiesMarkedForRemoval) { //We are interested only for aspects, therefore we are looking only for simple property paths if (pathOfPropertyMarkedForRemoval.contains(".")) { continue; } //If this property is not defined in the object's type definition, then it is an aspect if (!contentObjectTypeDefinition.hasCmsPropertyDefinition(pathOfPropertyMarkedForRemoval)) { ComplexCmsPropertyDefinition aspectDefinition = null; if (lazyLoader != null) { aspectDefinition = (ComplexCmsPropertyDefinition) lazyLoader.getDefinitionService() .getCmsDefinition(pathOfPropertyMarkedForRemoval, ResourceRepresentationType.DEFINITION_INSTANCE, false); } if (aspectDefinition == null) { logger.warn("Definition for aspect " + pathOfPropertyMarkedForRemoval + " was not found. Unable to marshal NULL value for this property which has been marked for removal."); continue; } marshallerVisitor.enableAspectDefinitionVisit(); aspectDefinition.accept(marshallerVisitor); } } } appendSchemaLocationToMarshaller(); return contentObjectTypeJaxb.getValue(); } private void appendSchemaLocationToMarshaller() throws PropertyException { if (MapUtils.isNotEmpty(marshallerVisitor.getXsiSchemaLocationMap())) { for (Map.Entry<QName, String> xsiSchemaLocationEntry : marshallerVisitor.getXsiSchemaLocationMap() .entrySet()) { SchemaUtils.appendSchemaLocationToMarshaller(marshaller, xsiSchemaLocationEntry.getKey().getNamespaceURI(), xsiSchemaLocationEntry.getValue(), xsiSchemaLocationEntry.getKey().getPrefix()); } marshallerVisitor.getXsiSchemaLocationMap().clear(); } } private String retrieveContentObjectType(ContentObject contentObject) { if (contentObject.getContentObjectType() == null) { throw new CmsException( "ContentObject " + contentObject.getSystemName() + " does not have content object type name"); } return contentObject.getContentObjectType(); } public void setMarshaller(Marshaller marshaller, boolean exportBinaryContent, boolean exportAllProperties) { this.marshaller = marshaller; this.serializeBinaryContent = exportBinaryContent; this.exportAllProperties = exportAllProperties; } @Override public ContentObject unmarshal(ContentObjectType contentObjectType) throws Exception { return null; /* ContentObject contentObject = null; if (contentObjectType !=null ){ contentObject = (ContentObject) contentObjectType.getCmsRepositoryEntityFromContextUsingCmsIdentifierOrReference(); if (contentObject != null){ return contentObject; } //Try with systemName if (contentObjectType.getSystemName() != null){ contentObject = (ContentObject) contentObjectType.getCmsRepositoryEntityFromContextUsingKey(contentObjectType.getSystemName()); if (contentObject != null){ return contentObject; } } if (unmarshaller == null){ createUnmarshaller(); } if (df == null){ try { df = DatatypeFactory.newInstance(); } catch (DatatypeConfigurationException e) { throw new CmsException(e); } } //Create content object contentObject = CmsRepositoryEntityFactoryForActiveClient.INSTANCE.getFactory().newContentObjectForType(contentObjectType.getContentObjectTypeName(), null); //Unmarshall basic attributes contentObject.setId(contentObjectType.getId()); contentObject.setSystemBuiltinEntity(contentObjectType.isSystemBuiltinEntity()); contentObject.setSystemName(contentObjectType.getSystemName()); contentObject.setOwner(contentObjectType.getOwner()); unmarshallCmsProperties(contentObject.getComplexCmsRootProperty(), contentObjectType.getCmsProperties()); contentObjectType.registerCmsRepositoryEntityToContext(contentObject); } return contentObject; */ } private void unmarshallCmsProperties(ComplexCmsProperty parentComplexCmsProperty, List<CmsPropertyType> cmsProperties) throws Exception { if (CollectionUtils.isNotEmpty(cmsProperties) && parentComplexCmsProperty != null) { List<String> propertyPathsWhoseDefaultValueHasBeenRemoved = new ArrayList<String>(); for (CmsPropertyType cmsPropertyType : cmsProperties) { if (cmsPropertyType.getQname() == null) { logger.warn( "Could not find name for cms property type {} which belongs to {}. Unmarshalling will ignore this property", cmsPropertyType.toString(), parentComplexCmsProperty.getFullPath()); continue; } //Retrieve property name String cmsPropertyName = cmsPropertyType.getQname().getLocalPart(); //Find its definition CmsProperty<?, ?> cmsProperty = null; if (parentComplexCmsProperty.isChildPropertyDefined(cmsPropertyName)) { CmsPropertyDefinition childPropertyDefinition = parentComplexCmsProperty.getPropertyDefinition() .getChildCmsPropertyDefinition(cmsPropertyName); //If property is a simple property or a single value complex loaded if (childPropertyDefinition.getValueType() != ValueType.Complex || !childPropertyDefinition.isMultiple()) { cmsProperty = parentComplexCmsProperty.getChildProperty(cmsPropertyName); } else { //Property is multiple complex property. Create a new instance cmsProperty = parentComplexCmsProperty .createNewValueForMulitpleComplexCmsProperty(cmsPropertyName); } //Removed default value rendered by Astroboa if (cmsProperty != null && childPropertyDefinition instanceof SimpleCmsPropertyDefinition && ((SimpleCmsPropertyDefinition) childPropertyDefinition).isSetDefaultValue() && !propertyPathsWhoseDefaultValueHasBeenRemoved.contains(cmsPropertyName)) { ((SimpleCmsProperty) cmsProperty).removeValues(); propertyPathsWhoseDefaultValueHasBeenRemoved.add(cmsPropertyName); } } else { //Create an aspect. This is done only in first level if (parentComplexCmsProperty instanceof ComplexCmsRootProperty) { cmsProperty = parentComplexCmsProperty.getChildProperty(cmsPropertyName); } } if (cmsProperty == null) { throw new CmsException("Could not find definition for property '" + cmsPropertyName + "'"); } unmarshallCmsProperty(cmsPropertyType, cmsProperty); } } } private void unmarshallCmsProperty(CmsPropertyType cmsPropertyType, CmsProperty<?, ?> cmsProperty) throws Exception { String content = null; switch (cmsProperty.getValueType()) { case Complex: final ComplexCmsProperty<?, ?> complexCmsProperty = ((ComplexCmsProperty<?, ?>) cmsProperty); if (!(cmsPropertyType instanceof ComplexCmsPropertyType)) { logger.warn( "CmsPropertyType {} is a simple type where as corresponding cms property is a complex property {}. Unmarhsalling will ignore this property", cmsPropertyType.getQname().toString(), complexCmsProperty.getFullPath()); return; } ComplexCmsPropertyType complexCmsPropertyType = (ComplexCmsPropertyType) cmsPropertyType; complexCmsProperty.setId(complexCmsPropertyType.getCmsIdentifier()); unmarshallCmsProperties(complexCmsProperty, complexCmsPropertyType.getCmsProperties()); break; case Boolean: content = retrieveContentFromSimpleCmsPropertyType(cmsPropertyType, cmsProperty); if (content != null) { ((BooleanProperty) cmsProperty).addSimpleTypeValue(Boolean.valueOf(content)); } break; case Date: content = retrieveContentFromSimpleCmsPropertyType(cmsPropertyType, cmsProperty); if (content != null) { ((CalendarProperty) cmsProperty) .addSimpleTypeValue(df.newXMLGregorianCalendar(content).toGregorianCalendar()); } break; case Double: content = retrieveContentFromSimpleCmsPropertyType(cmsPropertyType, cmsProperty); if (content != null) { ((DoubleProperty) cmsProperty).addSimpleTypeValue(Double.valueOf(content)); } break; case Long: content = retrieveContentFromSimpleCmsPropertyType(cmsPropertyType, cmsProperty); if (content != null) { ((LongProperty) cmsProperty).addSimpleTypeValue(Long.valueOf(content)); } break; case String: content = retrieveContentFromSimpleCmsPropertyType(cmsPropertyType, cmsProperty); if (content != null) { ((StringProperty) cmsProperty).addSimpleTypeValue(content); } break; case Binary: if (!(cmsPropertyType instanceof BinaryChannelType)) { logger.warn( "CmsPropertyType {} is not a binary type where as corresponding cms property is a binary property {}. Unmarhsalling will ignore this property", cmsPropertyType.getQname().toString(), cmsProperty.getFullPath()); return; } //Further unmarshall binary channel type to BinaryChannel BinaryChannel binaryChannel = getBinaryChannelAdapterFromUnmarshaller() .unmarshal(((BinaryChannelType) cmsPropertyType)); binaryChannel.setName(cmsProperty.getName()); ((BinaryProperty) cmsProperty).addSimpleTypeValue(binaryChannel); break; case ObjectReference: if (!(cmsPropertyType instanceof ContentObjectType)) { logger.warn( "CmsPropertyType {} is not a content object type where as corresponding cms property is a content object property {}. Unmarhsalling will ignore this property", cmsPropertyType.getQname().toString(), cmsProperty.getFullPath()); return; } //Ignore URL and use only type and identifier to create an empty content object //Use this instance to further unmarhsall ContentObjectType but do not proceed to its children ContentObject contentObject = unmarshal((ContentObjectType) cmsPropertyType); /*String contentObjectId = ((ContentObjectReferenceType)cmsPropertyType).getId(); String contentObjectType = ((ContentObjectReferenceType)cmsPropertyType).getContentObjectTypeName(); String contentObjectSystemName = ((ContentObjectReferenceType)cmsPropertyType).getSystemName(); String title = ((ContentObjectReferenceType)cmsPropertyType).getTitle(); ContentObject contentObject = CmsRepositoryEntityFactoryForActiveClient.INSTANCE.getFactory().newContentObjectForType(contentObjectType, "en"); //Locale plays no role contentObject.setId(contentObjectId); contentObject.setSystemName(contentObjectSystemName); if (title != null){ StringProperty contentObjectTitleProperty = (StringProperty) contentObject.getCmsProperty("profile.title"); if (contentObjectTitleProperty != null){ contentObjectTitleProperty.addSimpleTypeValue(title); } }*/ ((ObjectReferenceProperty) cmsProperty).addSimpleTypeValue(contentObject); break; case TopicReference: if (!(cmsPropertyType instanceof TopicType)) { logger.warn( "CmsPropertyType {} is not a topic property type where as corresponding cms property is a topic property {}. Unmarhsalling will ignore this property", cmsPropertyType.getQname().toString(), cmsProperty.getFullPath()); return; } //Further unmarshall topicType to TopicImpl Topic topic = getTopicAdapterFromUnmarshaller().unmarshal((TopicType) cmsPropertyType); if (StringUtils.isBlank(topic.getId()) && StringUtils.isBlank(topic.getName())) { throw new CmsException( "Unable to further unmarshal element " + ((TopicType) cmsPropertyType).getName().toString() + " Found no " + " topic cmsIdentifier or topic name"); } ((TopicReferenceProperty) cmsProperty).addSimpleTypeValue(topic); break; default: throw new CmsException("Unsupported ValueType " + cmsProperty.getValueType() + " for unmarshalling "); } } private String retrieveContentFromSimpleCmsPropertyType(CmsPropertyType cmsPropertyType, CmsProperty<?, ?> cmsProperty) { if (!(cmsPropertyType instanceof SimpleCmsPropertyType)) { logger.warn( "CmsPropertyType {} is not a simple type where as corresponding cms property is a simple property {}. Unmarhsalling will ignore this property", cmsPropertyType.getQname().toString(), cmsProperty.getFullPath()); return null; } SimpleCmsPropertyType simpleCmsPropertyType = (SimpleCmsPropertyType) cmsPropertyType; return simpleCmsPropertyType.getContent(); } private BinaryChannelAdapter getBinaryChannelAdapterFromUnmarshaller() { if (unmarshaller.getAdapter(BinaryChannelAdapter.class) == null) { unmarshaller.setAdapter(new BinaryChannelAdapter(false)); } return unmarshaller.getAdapter(BinaryChannelAdapter.class); } private TopicAdapter getTopicAdapterFromUnmarshaller() { if (unmarshaller.getAdapter(TopicAdapter.class) == null) { unmarshaller.setAdapter(new TopicAdapter()); } return unmarshaller.getAdapter(TopicAdapter.class); } private SpaceAdapter getSpaceAdapterFromUnmarshaller() { if (unmarshaller.getAdapter(SpaceAdapter.class) == null) { unmarshaller.setAdapter(new SpaceAdapter()); } return unmarshaller.getAdapter(SpaceAdapter.class); } private void createUnmarshaller() throws JAXBException { //unmarshaller = CmsEntitySerialization.Context.createUnmarshaller(); //Must specify our own event handler in order to propagate SAX exceptions unmarshaller.setEventHandler(new AstroboaValidationEventHandler()); unmarshaller.setAdapter(this); } }