/*
* 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 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Astroboa. If not, see <http://www.gnu.org/licenses/>.
*/
package org.betaconceptframework.astroboa.engine.jcr.io.contenthandler;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Deque;
import java.util.List;
import javax.xml.XMLConstants;
import javax.xml.datatype.DatatypeConfigurationException;
import javax.xml.datatype.DatatypeFactory;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.collections.CollectionUtils;
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.CmsProperty;
import org.betaconceptframework.astroboa.api.model.CmsRepositoryEntity;
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.ObjectReferenceProperty;
import org.betaconceptframework.astroboa.api.model.RepositoryUser;
import org.betaconceptframework.astroboa.api.model.SimpleCmsProperty;
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.TopicReferenceProperty;
import org.betaconceptframework.astroboa.api.model.ValueType;
import org.betaconceptframework.astroboa.api.model.definition.CmsPropertyDefinition;
import org.betaconceptframework.astroboa.api.model.definition.Localization;
import org.betaconceptframework.astroboa.api.model.definition.SimpleCmsPropertyDefinition;
import org.betaconceptframework.astroboa.api.model.exception.CmsException;
import org.betaconceptframework.astroboa.engine.jcr.io.Deserializer;
import org.betaconceptframework.astroboa.engine.jcr.io.ImportContext;
import org.betaconceptframework.astroboa.engine.jcr.io.ImportedEntity;
import org.betaconceptframework.astroboa.engine.model.jaxb.Repository;
import org.betaconceptframework.astroboa.model.factory.CmsRepositoryEntityFactoryForActiveClient;
import org.betaconceptframework.astroboa.model.impl.RepositoryUserImpl;
import org.betaconceptframework.astroboa.model.impl.item.CmsBuiltInItem;
import org.betaconceptframework.astroboa.util.CmsConstants;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;
/**
*
* Main import content handler responsible to import XML.
*
* For JSON import use JsonImportContentHandler
*
* @author Gregory Chomatas (gchomatas@betaconcept.com)
* @author Savvas Triantafyllou (striantafyllou@betaconcept.com)
*
*/
public class ImportContentHandler<T> implements ContentHandler{
private Logger logger = LoggerFactory.getLogger(getClass());
private ImportContext importContext;
private StringBuilder elementContent = new StringBuilder();
private Deque<ImportedEntity> cmsRepositoryEntityQueue = new ArrayDeque<ImportedEntity>();
private T importResult;
private Class<T> resultType;
/*
* During import some elements may be ignored because they
* have already been processed. This stands for topics or repository users
* which may be encountered more than once in side an XML or JSON
*
* This variable holds the main element whose content (child elements) are ignored.
* Only when this elements is closed, import is back to normal.
*/
private String elementNameToBeIgnored = null;
private DatatypeFactory df;
private Deserializer deserializer;
public ImportContentHandler(Class<T> resultType, Deserializer deserializer){
this(new ImportContext(), resultType, deserializer);
}
public ImportContentHandler(ImportContext importContext, Class<T> resultType, Deserializer deserializer){
this.importContext = importContext;
this.resultType = resultType;
this.deserializer = deserializer;
try {
df = DatatypeFactory.newInstance();
} catch (DatatypeConfigurationException e) {
throw new CmsException(e);
}
}
private boolean doNotProcessEvent() {
return elementNameToBeIgnored != null;
}
@Override
public void characters(char[] ch, int start, int length)
throws SAXException {
if (doNotProcessEvent()){
return;
}
elementContent.append(ch, start, length);
}
@Override
public void endDocument() throws SAXException {
elementContent = null;
elementNameToBeIgnored = null;
importContext.dispose();
importContext = null;
}
@Override
public void startDocument() throws SAXException {
clearElementContent();
elementNameToBeIgnored = null;
cmsRepositoryEntityQueue.clear();
importResult = null;
}
private void createRootEntity(String uri, String rootElementName, Attributes atts) throws SAXException {
if (Topic.class.isAssignableFrom(resultType)){
importResult = (T) createNewTopic(atts, rootElementName);
}
else if (Taxonomy.class.isAssignableFrom(resultType)){
importResult = (T) createNewTaxonomy(atts, rootElementName);
}
else if (RepositoryUser.class.isAssignableFrom(resultType)){
importResult = (T) createNewRepositoryUser(atts, rootElementName);
}
else if (Repository.class.isAssignableFrom(resultType)){
importResult = (T) new Repository();
}
else if (Space.class.isAssignableFrom(resultType)){
importResult = (T) createNewSpace(atts, rootElementName);
}
else if (ContentObject.class.isAssignableFrom(resultType)){
importResult = (T) createNewContentObject(atts, rootElementName, uri, null);
}
else if (List.class.isAssignableFrom(resultType)){
importResult = (T) new ArrayList();
}
else{
throw new SAXException("Unsupported type of imported Entity "+ resultType.getName());
}
pushEntity(rootElementName, importResult, atts);
elementNameToBeIgnored = null;
}
private void importAttributes(Attributes atts) throws SAXException {
if (atts != null && atts.getLength() >0){
for (int i=0;i<atts.getLength();i++){
//Ignore attributes with specific namespaces
String uri = atts.getURI(i);
if (StringUtils.equals(uri, XMLConstants.XMLNS_ATTRIBUTE_NS_URI) ||
StringUtils.equals(uri, XMLConstants.XML_NS_URI) ||
StringUtils.equals(uri, XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI) ||
StringUtils.equals(uri, XMLConstants.W3C_XML_SCHEMA_NS_URI) ||
StringUtils.equals(uri, XMLConstants.W3C_XPATH_DATATYPE_NS_URI)){
continue;
}
addAttributeToImportedEntity(atts.getLocalName(i), atts.getValue(i));
}
}
}
@Override
public void startElement(String uri, String localName, String qName,
Attributes atts) throws SAXException {
logger.debug("Importing element name {}, uri {}", localName, uri);
if (doNotProcessEvent()){
return;
}
if (importResult == null){
createRootEntity(uri, localName, atts);
}
else{
//Queue should not be empty
throwExceptionIfQeueIsEmpty(uri, localName);
Object currentEntity = getCurrentEntityImported();
// Element corresponds to a cms property
if (currentEntity instanceof ContentObject){
if (CmsConstants.OWNER_ELEMENT_NAME.equals(localName)){
if (processOwner(atts)){
return;
}
}
else{
processCmsProperty(localName, atts, uri);
return ;
}
}
else if (currentEntity instanceof CmsProperty ){
processCmsProperty(localName, atts, uri);
return ;
}
else if (currentEntity instanceof BinaryChannel &&
CmsConstants.CONTENT_ELEMENT_NAME.equals(localName)){
//Element is content , which is defined in context of BinaryChannel
//It will be processed when closing this element
cmsRepositoryEntityQueue.peek().processingRawData(true);
return;
}
else if (CmsConstants.LOCALIZED_LABEL_ELEMENT_NAME.equals(localName)){
//Depending on source XML or JSON attribute for lang may appear differently
String langValue = getValueForAttribute(CmsConstants.LANG_ATTRIBUTE_NAME_WITH_PREFIX, atts);
if (langValue == null){
langValue = getValueForAttribute(CmsConstants.LANG_ATTRIBUTE_NAME, atts);
}
if (langValue != null){
addAttributeToImportedEntity(CmsConstants.LANG_ATTRIBUTE_NAME_WITH_PREFIX, langValue);
}
else{
//Found no lang attribute.
if (atts.getLength() > 0 && currentEntity instanceof Localization){
addLabelsForLocaleToImportedEntity(atts);
}
}
return;
}
else if (CmsConstants.OWNER_ELEMENT_NAME.equals(localName)){
if (processOwner(atts)){
return;
}
}
else if (shouldIgnoreElement(localName)){
return ;
}
else{
if (currentEntity instanceof Topic){
//Expecting taxonomy, parentTopic or child topic
final Topic currentlyImportedTopic = (Topic)currentEntity;
if (CmsBuiltInItem.Taxonomy.getLocalPart().equals(localName)){
Taxonomy taxonomy = createNewTaxonomy(atts, localName);
currentlyImportedTopic.setTaxonomy(taxonomy);
pushEntity(localName, taxonomy, atts);
return;
}
else if (CmsBuiltInItem.Topic.getLocalPart().equals(localName)){
//Perform an initial check if topic name already exists
if (atts!=null && importContext.isEntityCached(getValueForAttribute(CmsBuiltInItem.Name.getLocalPart(), atts))){
throw new SAXException("Topic with name "+getValueForAttribute(CmsBuiltInItem.Name.getLocalPart(), atts) +" has been already imported");
}
Topic childTopic = createNewTopic(atts, localName);
currentlyImportedTopic.addChild(childTopic);
if (childTopic.getTaxonomy() == null && currentlyImportedTopic.getTaxonomy() != null){
childTopic.setTaxonomy(currentlyImportedTopic.getTaxonomy());
}
pushEntity(localName, childTopic, atts);
return;
}
else if (CmsConstants.PARENT_TOPIC.equals(localName)){
Topic parentTopic = createNewTopic(atts, localName);
currentlyImportedTopic.setParent(parentTopic);
pushEntity(localName, parentTopic, atts);
return;
}
}
else if (currentEntity instanceof Space){
//Expecting parentSpace or child space
if (CmsBuiltInItem.Space.getLocalPart().equals(localName)){
Space space = createNewSpace(atts, localName);
((Space)currentEntity).addChild(space);
pushEntity(localName, space, atts);
return;
}
else if (CmsConstants.PARENT_SPACE.equals(localName)){
Space space = createNewSpace(atts, localName);
((Space)currentEntity).setParent(space);
pushEntity(localName, space, atts);
return;
}
}
else if (currentEntity instanceof Taxonomy){
//Expecting child topic
if (CmsBuiltInItem.Topic.getLocalPart().equals(localName)){
if (atts!=null && importContext.isEntityCached(getValueForAttribute(CmsBuiltInItem.Name.getLocalPart(), atts))){
throw new SAXException("Topic with name "+getValueForAttribute(CmsBuiltInItem.Name.getLocalPart(), atts) +" has been already imported");
}
Topic topic = createNewTopic(atts, localName);
((Taxonomy)currentEntity).addRootTopic(topic);
pushEntity(localName, topic, atts);
return;
}
}
else if (currentEntity instanceof RepositoryUser){
if (CmsBuiltInItem.Space.getLocalPart().equals(localName)){
Space space = createNewSpace(atts, localName);
((RepositoryUserImpl)currentEntity).setSpace(space);
pushEntity(localName, space, atts);
return;
}
else if (CmsBuiltInItem.Taxonomy.getLocalPart().equals(localName)){
Taxonomy taxonomy = createNewTaxonomy(atts, localName);
((RepositoryUserImpl)currentEntity).setFolksonomy(taxonomy);
pushEntity(localName, taxonomy, atts);
return;
}
}
else if (currentEntity instanceof Repository){
if (CmsBuiltInItem.Taxonomy.getLocalPart().equals(localName)){
Taxonomy taxonomy = createNewTaxonomy(atts, localName);
pushEntity(localName, taxonomy, atts);
return;
}
else if (CmsBuiltInItem.Topic.getLocalPart().equals(localName)){
Topic topic = createNewTopic(atts, localName);
pushEntity(localName, topic, atts);
return;
}
else if (CmsBuiltInItem.OrganizationSpace.getLocalPart().equals(localName)){
Space space = createNewSpace(atts, localName);
pushEntity(localName, space, atts);
return;
}
else if (CmsBuiltInItem.RepositoryUser.getLocalPart().equals(localName)){
RepositoryUser repositoryUser = createNewRepositoryUser(atts, localName);
pushEntity(localName, repositoryUser, atts);
return;
}
else{
ContentObject contentObject = createNewContentObject(atts, localName, uri, null);
pushEntity(localName, contentObject, atts);
return ;
}
}
else if (currentEntity instanceof List){
if (CmsBuiltInItem.Taxonomy.getLocalPart().equals(localName)){
Taxonomy taxonomy = createNewTaxonomy(atts, localName);
((List)currentEntity).add(taxonomy);
pushEntity(localName, taxonomy, atts);
return;
}
else if (CmsBuiltInItem.Space.getLocalPart().equals(localName)){
Space space = createNewSpace(atts, localName);
((List)currentEntity).add(space);
pushEntity(localName, space, atts);
return;
}
else if (CmsBuiltInItem.RepositoryUser.getLocalPart().equals(localName)){
RepositoryUser repositoryUser = createNewRepositoryUser(atts, localName);
((List)currentEntity).add(repositoryUser);
pushEntity(localName, repositoryUser, atts);
return;
}
else if (CmsBuiltInItem.Topic.getLocalPart().equals(localName)){
Topic topic = createNewTopic(atts, localName);
((List)currentEntity).add(topic);
pushEntity(localName, topic, atts);
return;
}
else{
ContentObject contentObject = createNewContentObject(atts, localName, uri, null);
((List)currentEntity).add(contentObject);
pushEntity(localName, contentObject, atts);
return ;
}
}
}
throw new SAXException("Unexpected element "+localName);
}
}
public Object getCurrentEntityImported() {
if (cmsRepositoryEntityQueue.isEmpty()){
return null;
}
return cmsRepositoryEntityQueue.peek().getEntity();
}
private boolean shouldIgnoreElement(String localName) {
return StringUtils.equals(localName, CmsBuiltInItem.Localization.getLocalPart()) ||
StringUtils.equals(localName, CmsConstants.ROOT_TOPICS) ||
StringUtils.equals(localName, CmsConstants.CHILD_SPACES) ||
StringUtils.equals(localName, CmsConstants.CHILD_TOPICS) ||
(cmsRepositoryEntityQueue.peek().getEntity() instanceof Repository &&
(StringUtils.equals(localName, CmsConstants.OBJECTS_ELEMENT_NAME) ||
StringUtils.equals(localName, CmsConstants.TAXONOMIES_ELEMENT_NAME) ||
StringUtils.equals(localName, CmsConstants.TOPICS_ELEMENT_NAME) ||
StringUtils.equals(localName, CmsConstants.REPOSITORY_USERS_ELEMENT_NAME))) ||
(cmsRepositoryEntityQueue.peek().getEntity() instanceof List &&
( StringUtils.equals(localName, CmsConstants.RESOURCE_COLLECTION) ||
StringUtils.equals(localName, CmsConstants.RESOURCE_RESPONSE) ||
StringUtils.equals(localName, CmsConstants.TOTAL_RESOURCE_COUNT) ||
StringUtils.equals(localName, CmsConstants.OFFSET) ||
StringUtils.equals(localName, CmsConstants.LIMIT) )
);
}
@Override
public void endElement(String uri, String localName, String qName)
throws SAXException {
logger.debug("Ending element {}",localName);
ImportedEntity entityWhoseImportHasFinished = null;
if (elementNameToBeIgnored != null){
//Ending element belongs to a part of source which is ignored
//Check whether this part has ended or not
//In case ignored part has ended, current imported entity is returned
//in order to be further processed
entityWhoseImportHasFinished = checkIgnoredPartHasEnded(localName);
}
else if (StringUtils.equals(CmsConstants.LOCALIZED_LABEL_ELEMENT_NAME, localName)){
addLocalizedLabelToImportedEntity(retrieveElementContentValue());
clearElementContent();
return ;
}
else if (StringUtils.equals(CmsConstants.CONTENT_ELEMENT_NAME, localName) &&
! cmsRepositoryEntityQueue.isEmpty() &&
cmsRepositoryEntityQueue.peek().entityIsABinaryChannelAndRawDataElementIsBeingProcessed()){
//Content element is ending. Add content to binaryChannel
addContentToBinaryChannel(retrieveElementContentValue());
clearElementContent();
cmsRepositoryEntityQueue.peek().processingRawData(false);
return;
}
else if (entityHasEnded(localName)){
entityWhoseImportHasFinished = removeEntityFromQueue();
}
if (entityWhoseImportHasFinished != null){
entityWhoseImportHasFinished.completeEntityImport((retrieveElementContentValue()));
if (entityWhoseImportHasFinished.getEntity() instanceof CmsRepositoryEntity){
CmsRepositoryEntity cmsRepositoryEntity = (CmsRepositoryEntity)entityWhoseImportHasFinished.getEntity();
boolean cacheEntity = true;
if (! cmsRepositoryEntityQueue.isEmpty() &&
( cmsRepositoryEntityQueue.peek().getEntity() instanceof Repository ||
cmsRepositoryEntityQueue.peek().getEntity() instanceof List) ){
//Repository or Resource Collection import under way. Send entity to importer in order to be saved accordingly
cmsRepositoryEntity = deserializer.save(cmsRepositoryEntity);
}
else if (cmsRepositoryEntity instanceof BinaryChannel){
deserializer.loadBinaryChannelContent((BinaryChannel)cmsRepositoryEntity);
}
else{
//Special case. If entity currently imported is a complex property but has no child properties
//then remove this property as user has specified a NULL value (in JSON) or an empty tag (in XML),
//marking this property for removal.
if ( (cmsRepositoryEntity instanceof ComplexCmsProperty) && (!(cmsRepositoryEntity instanceof ComplexCmsRootProperty))){
ComplexCmsProperty complexProperty = ((ComplexCmsProperty)cmsRepositoryEntity);
if (complexProperty.getChildProperties() == null || complexProperty.getChildProperties().isEmpty()){
((ComplexCmsProperty)complexProperty).getParentProperty().removeChildProperty(complexProperty.getPath());
cacheEntity = false;
}
}
}
if (cacheEntity){
importContext.cacheEntity(cmsRepositoryEntity);
}
}
}
clearElementContent();
}
private String retrieveElementContentValue() {
return StringUtils.trimToNull(elementContent.toString());
}
private boolean processOwner(Attributes atts) throws SAXException {
ImportedEntity currentImportedEntity = cmsRepositoryEntityQueue.peek();
if (currentImportedEntity == null){
throw new CmsException("No parent entity found for element 'owner' with attributes "+ atts.toString());
}
if (currentImportedEntity.hasOwnerElement()){
RepositoryUser owner = createNewRepositoryUser(atts, CmsConstants.OWNER_ELEMENT_NAME);
if (currentImportedEntity.getEntity() instanceof ContentObject){
((ContentObject)currentImportedEntity.getEntity()).setOwner(owner);
}
else if (currentImportedEntity.getEntity() instanceof Topic){
((Topic)currentImportedEntity.getEntity()).setOwner(owner);
}
else if (currentImportedEntity .getEntity() instanceof Space){
((Space)currentImportedEntity.getEntity()).setOwner(owner);
}
else{
logger.debug("Owner {} has not been assigned to parent entity {}", owner.toString(), currentImportedEntity.getEntity());
}
pushEntity(CmsConstants.OWNER_ELEMENT_NAME, owner, atts);
return true;
}
return false;
}
private RepositoryUser createNewRepositoryUser(Attributes atts, String entityLocalName) {
RepositoryUser repositoryUser = retrieveOrCreateEntity(RepositoryUser.class, atts, entityLocalName);
repositoryUser.setExternalId(getValueForAttribute(CmsBuiltInItem.ExternalId.getLocalPart(), atts));
repositoryUser.setLabel(getValueForAttribute(CmsBuiltInItem.Label.getLocalPart(), atts));
return repositoryUser;
}
private <T extends CmsRepositoryEntity> T retrieveOrCreateEntity(Class<T> entityClass, Attributes atts, String entityLocalName){
T entity = null;
boolean referenceIdNotFoundInMap = false;
String cacheKey = null;
boolean cacheKeyIsId = false;
if (atts != null && atts.getLength() > 0){
cacheKey = getValueForAttribute(CmsBuiltInItem.CmsIdentifier.getLocalPart(), atts);
if (cacheKey == null){
cacheKey = getValueForAttribute(CmsBuiltInItem.Name.getLocalPart(), atts);
}
else{
cacheKeyIsId =true;
}
if (cacheKey == null && ContentObject.class.isAssignableFrom(entityClass)){
cacheKey = getValueForAttribute(CmsBuiltInItem.SystemName.getLocalPart(), atts);
}
else if (cacheKey == null && RepositoryUser.class.isAssignableFrom(entityClass)){
cacheKey = getValueForAttribute(CmsBuiltInItem.ExternalId.getLocalPart(), atts);
}
if (cacheKey != null){
if (importContext.isEntityCached(cacheKey)){
elementNameToBeIgnored = entityLocalName;
return (T) importContext.getEntityFromCache(cacheKey);
}
else{
referenceIdNotFoundInMap = true;
}
}
}
if (entityClass == RepositoryUser.class){
entity = (T) CmsRepositoryEntityFactoryForActiveClient.INSTANCE.getFactory().newRepositoryUser();
}
else if (entityClass == Topic.class){
entity = (T) CmsRepositoryEntityFactoryForActiveClient.INSTANCE.getFactory().newTopic();
}
else if (entityClass == Space.class){
entity = (T) CmsRepositoryEntityFactoryForActiveClient.INSTANCE.getFactory().newSpace();
}
else if (entityClass == Taxonomy.class){
entity = (T) CmsRepositoryEntityFactoryForActiveClient.INSTANCE.getFactory().newTaxonomy();
}
else if (entityClass == BinaryChannel.class){
entity = (T) CmsRepositoryEntityFactoryForActiveClient.INSTANCE.getFactory().newBinaryChannel();
}
else {
throw new CmsException("Unknown entity type "+ entityClass);
}
if (referenceIdNotFoundInMap){
if (entity.getId() == null && cacheKeyIsId){
entity.setId(cacheKey);
importContext.cacheEntity(entity);
}
else if (cacheKey !=null){
importContext.cacheEntity(cacheKey, entity);
}
}
return entity;
}
private void throwExceptionIfQeueIsEmpty(String uri, String localName)
throws SAXException {
if (cmsRepositoryEntityQueue.isEmpty()){
throw new SAXException("Element {"+uri+"}"+localName+" was not imported. Entity queue is empty");
}
}
private ContentObject createNewContentObject(Attributes atts, String localName, String uri, String expectedContentType) {
String contentType = getValueForAttribute(CmsBuiltInItem.ContentObjectTypeName.getLocalPart(), atts);
if (StringUtils.isBlank(contentType) && StringUtils.isNotBlank(expectedContentType)){
contentType = expectedContentType;
}
if (contentType == null){
logger.info("Could not identify the type of the object reference of the element "+localName+".");
return null;
}
try{
ContentObject contentObject = CmsRepositoryEntityFactoryForActiveClient.INSTANCE.getFactory().newObjectForType(contentType);
contentObject.setContentObjectType(getValueForAttribute(CmsBuiltInItem.ContentObjectTypeName.getLocalPart(), atts));
contentObject.setSystemName(getValueForAttribute(CmsBuiltInItem.SystemName.getLocalPart(), atts));
return contentObject;
}
catch(Exception e){
logger.warn("Element "+localName+"'s corresponds to an unknown content type "+contentType+".", e);
return null;
}
}
private String getValueForAttribute(String attributeName, Attributes atts){
final int index = atts.getIndex(attributeName);
if (index > -1){
return atts.getValue(index);
}
return null;
}
private void pushEntity(String entityLocalName, Object entity, Attributes atts) throws SAXException {
pushEntity(entityLocalName, entity, atts, false);
}
private void pushEntity(String entityLocalName, Object entity, Attributes atts, boolean entityRepresentsAContentObjectReference) throws SAXException {
ImportedEntity importedEntity = new ImportedEntity(entityLocalName,entity, df,entityRepresentsAContentObjectReference);
cmsRepositoryEntityQueue.push(importedEntity);
logger.debug("Adding to queue name {} entity {}", entityLocalName, entity);
importAttributes(atts);
}
private boolean entityHasEnded(String localName) {
return ! cmsRepositoryEntityQueue.isEmpty() &&
StringUtils.equals(localName, cmsRepositoryEntityQueue.peek().getName());
}
private void addContentToBinaryChannel(String content) {
if (content != null){
((BinaryChannel)cmsRepositoryEntityQueue.peek().getEntity()).setContent(Base64.decodeBase64(content));
}
}
private void addLabelsForLocaleToImportedEntity(Attributes atts) {
if (!cmsRepositoryEntityQueue.isEmpty()){
if (atts != null && atts.getLength() >0){
for (int i=0;i<atts.getLength();i++){
cmsRepositoryEntityQueue.peek().addLocalizedLabel(atts.getLocalName(i), atts.getValue(i));
}
}
}
else{
logger.warn("No entity found in queue. Labels were not imported", atts);
}
}
private void addLocalizedLabelToImportedEntity(String localizedLabel) {
if (!cmsRepositoryEntityQueue.isEmpty()){
cmsRepositoryEntityQueue.peek().addLocalizedLabel(localizedLabel);
}
else{
logger.warn("No entity found in queue. Label {} was not imported", localizedLabel);
}
}
public void addAttributeToImportedEntity(String attributeName, String attributeValue) throws SAXException {
boolean attributeHasBeenAdded = false;
if (!cmsRepositoryEntityQueue.isEmpty()){
final ImportedEntity firstEntityInQueue = cmsRepositoryEntityQueue.peek();
final Object entity = firstEntityInQueue.getEntity();
attributeHasBeenAdded = firstEntityInQueue.addAttribute(attributeName, attributeValue);
if (attributeHasBeenAdded &&
( entity instanceof ContentObject ||
entity instanceof Topic ||
entity instanceof Taxonomy ||
entity instanceof Space ||
entity instanceof RepositoryUser
)
){
if (CmsBuiltInItem.CmsIdentifier.getLocalPart().equals(attributeName)){
importContext.cacheEntity((CmsRepositoryEntity) entity);
}
}
if (! attributeHasBeenAdded && attributeName != null && (
entity instanceof ContentObject ||
entity instanceof CmsProperty )){
//Probably a cms property
startElement(null, attributeName, null, null);
if (attributeValue != null){
characters(attributeValue.toCharArray(), 0, attributeValue.length());
}
endElement(null, attributeName, null);
attributeHasBeenAdded = true;
}
}
if (! attributeHasBeenAdded){
logger.warn("Attribute {} with value {} was not imported. Entity in queue {}",
new Object[]{attributeName, attributeValue, cmsRepositoryEntityQueue.isEmpty()? " NONE ":
cmsRepositoryEntityQueue.peek().toString()});
}
}
private void clearElementContent() {
elementContent.delete(0, elementContent.length());
elementContent.trimToSize();
}
private ImportedEntity checkIgnoredPartHasEnded(String localName) {
if (StringUtils.equals(elementNameToBeIgnored, localName)){
elementNameToBeIgnored = null;
return removeEntityFromQueue();
}
else{
clearElementContent();
return null;
}
}
private ImportedEntity removeEntityFromQueue() {
ImportedEntity removedEntity = cmsRepositoryEntityQueue.poll();
logger.debug("Removing entity name {} {} from queue", removedEntity != null ? removedEntity.getName() : " null",
removedEntity != null ? removedEntity.getEntity().toString() : null);
return removedEntity;
}
private void processCmsProperty(String localName, Attributes atts, String uri) throws SAXException {
ImportedEntity importedEntity = cmsRepositoryEntityQueue.peek();
if (importedEntity == null){
throw new CmsException("No parent property found for element "+localName);
}
CmsPropertyDefinition cmsPropertyDefinition = null;
CmsProperty cmsProperty = null;
ComplexCmsProperty parentComplexCmsProperty = null;
if (importedEntity.getEntity() instanceof ContentObject){
//Special case. Element 'title' of a content object reference might be imported
if (importedEntity.representsAReferenceToAContentObject() && CmsConstants.TITLE_ELEMENT_NAME.equals(localName)){
cmsPropertyDefinition = ((ContentObject)importedEntity.getEntity()).getTypeDefinition().getCmsPropertyDefinition("profile.title");
cmsProperty = ((ContentObject)importedEntity.getEntity()).getCmsProperty("profile.title");
}
else{
cmsPropertyDefinition = ((ContentObject)importedEntity.getEntity()).getTypeDefinition().getCmsPropertyDefinition(localName);
}
if (cmsPropertyDefinition == null){
//Property is an aspect. It is safe to call getCmsProperty
cmsProperty = ((ContentObject)importedEntity.getEntity()).getCmsProperty(localName);
}
else{
parentComplexCmsProperty = ((ContentObject)importedEntity.getEntity()).getComplexCmsRootProperty();
}
}
else if (importedEntity.getEntity() instanceof ComplexCmsProperty){
cmsPropertyDefinition = ((ComplexCmsProperty)importedEntity.getEntity()).getPropertyDefinition().getChildCmsPropertyDefinition(localName);
if (cmsPropertyDefinition == null){
throw new CmsException("Invalid property "+localName+ " for parent property "+
((ComplexCmsProperty)importedEntity.getEntity()).getFullPath());
}
parentComplexCmsProperty = (ComplexCmsProperty)importedEntity.getEntity();
}
else if (importedEntity.getEntity() instanceof BinaryProperty){
//Leave entity as is
elementNameToBeIgnored = localName;
return;
}
else {
throw new CmsException("Expected to find either a ComplexCmsProperty or a BinaryProperty or a ContentObject as a parent for element "+ localName + " " +
" but found "+ importedEntity.getName()+ " as "+ importedEntity.getEntity().toString()+ " instead");
}
if (cmsProperty == null){
if (cmsPropertyDefinition == null){
throw new CmsException("Invalid child property "+localName+ " parent entity "+
importedEntity.getEntity().toString());
}
if (cmsPropertyDefinition.isMultiple() && cmsPropertyDefinition.getValueType() == ValueType.Complex){
cmsProperty = parentComplexCmsProperty.createNewValueForMulitpleComplexCmsProperty(localName);
}
else{
boolean propertyAlreadyLoaded = parentComplexCmsProperty.isChildPropertyLoaded(localName);
cmsProperty = parentComplexCmsProperty.getChildProperty(localName);
if (cmsProperty != null && cmsPropertyDefinition instanceof SimpleCmsPropertyDefinition &&
((SimpleCmsPropertyDefinition)cmsPropertyDefinition).getDefaultValue() != null &&
! propertyAlreadyLoaded){
//remove default value. Property has been loaded for the first time and contains its default value
//Default value should be removed
((SimpleCmsProperty)cmsProperty).removeValues();
}
}
if (cmsProperty == null){
throw new CmsException("Invalid property "+localName+ " for parent property "+
cmsPropertyDefinition.getFullPath());
}
}
if (cmsProperty.getValueType() == ValueType.Complex){
pushEntity(localName, cmsProperty, atts);
}
else if (cmsProperty.getValueType() == ValueType.Binary){
BinaryChannel binaryChannel = populateBinaryChannelProperty(((BinaryProperty)cmsProperty), atts);
pushEntity(localName, binaryChannel, atts);
}
else if (cmsProperty.getValueType() == ValueType.TopicReference){
Topic topic = populateTopicProperty(((TopicReferenceProperty)cmsProperty), atts, localName);
pushEntity(localName, topic, atts);
}
else if (cmsProperty.getValueType() == ValueType.ObjectReference){
ContentObject contentObject = populateContentObjectProperty(((ObjectReferenceProperty)cmsProperty), atts, localName, uri);
if (contentObject!=null){
pushEntity(localName, contentObject, atts, true);
}
}
else {
pushEntity(localName, cmsProperty, atts);
}
}
private ContentObject populateContentObjectProperty(
ObjectReferenceProperty contentObjectProperty, Attributes atts,
String localName, String uri) {
String expectedContentType = null;
if (contentObjectProperty != null && contentObjectProperty.getPropertyDefinition() != null &&
CollectionUtils.isNotEmpty(contentObjectProperty.getPropertyDefinition().getExpandedAcceptedContentTypes()) &&
contentObjectProperty.getPropertyDefinition().getExpandedAcceptedContentTypes().size() == 1){
expectedContentType = contentObjectProperty.getPropertyDefinition().getExpandedAcceptedContentTypes().get(0);
}
ContentObject contentObject = createNewContentObject(atts, localName, uri, expectedContentType);
if (contentObject!=null){
contentObjectProperty.addSimpleTypeValue(contentObject);
}
return contentObject;
}
private Topic populateTopicProperty(TopicReferenceProperty topicProperty,
Attributes atts, String entityLocalName) {
Topic topic = createNewTopic(atts, entityLocalName);
topicProperty.addSimpleTypeValue(topic);
return topic;
}
private Topic createNewTopic(Attributes atts, String entityLocalName) {
Topic topic = retrieveOrCreateEntity(Topic.class, atts, entityLocalName);
if (elementNameToBeIgnored == null){
topic.setName(getValueForAttribute(CmsBuiltInItem.Name.getLocalPart(), atts));
}
return topic;
}
private Space createNewSpace(Attributes atts, String entityLocalName) {
Space space = retrieveOrCreateEntity(Space.class, atts, entityLocalName);
if (elementNameToBeIgnored == null){
space.setName(getValueForAttribute(CmsBuiltInItem.Name.getLocalPart(), atts));
}
return space;
}
private Taxonomy createNewTaxonomy(Attributes atts, String entityLocalName) {
Taxonomy taxonomy = retrieveOrCreateEntity(Taxonomy.class, atts, entityLocalName);
if (elementNameToBeIgnored == null){
taxonomy.setName(getValueForAttribute(CmsBuiltInItem.Name.getLocalPart(), atts));
}
return taxonomy;
}
private BinaryChannel populateBinaryChannelProperty(
BinaryProperty binaryProperty, Attributes atts) {
BinaryChannel binaryChannel = retrieveOrCreateEntity(BinaryChannel.class, atts, binaryProperty.getName());
binaryChannel.setName(binaryProperty.getName());
binaryProperty.addSimpleTypeValue(binaryChannel);
return binaryChannel;
}
public T getImportResult(){
return importResult;
}
/*
* Unused methods
*/
@Override
public void endPrefixMapping(String prefix) throws SAXException {
// TODO Auto-generated method stub
}
@Override
public void ignorableWhitespace(char[] ch, int start, int length)
throws SAXException {
}
@Override
public void processingInstruction(String target, String data)
throws SAXException {
}
@Override
public void setDocumentLocator(Locator locator) {
}
@Override
public void skippedEntity(String name) throws SAXException {
}
@Override
public void startPrefixMapping(String prefix, String uri)
throws SAXException {
}
}