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 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 { } }