/*
*
* This is a simple Content Management System (CMS)
* Copyright (C) 2010 Imran M Yousuf (imyousuf@smartitengineering.com)
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.smartitengineering.cms.api.impl.type;
import com.smartitengineering.cms.api.common.MediaType;
import com.smartitengineering.cms.api.common.SearchResult;
import com.smartitengineering.cms.api.exception.InvalidReferenceException;
import com.smartitengineering.cms.api.type.CollectionDataType;
import com.smartitengineering.cms.api.type.CompositeDataType;
import com.smartitengineering.cms.api.type.ContentDataType;
import com.smartitengineering.cms.api.type.ContentStatus;
import com.smartitengineering.cms.api.type.ContentType;
import com.smartitengineering.cms.api.type.ContentTypeId;
import com.smartitengineering.cms.api.factory.type.ContentTypeLoader;
import com.smartitengineering.cms.api.factory.type.WritableContentType;
import com.smartitengineering.cms.api.impl.content.SearchResultImpl;
import com.smartitengineering.cms.api.type.ContentCoProcessorDef;
import com.smartitengineering.cms.api.type.EnumDataType;
import com.smartitengineering.cms.api.type.FieldDef;
import com.smartitengineering.cms.api.type.Filter;
import com.smartitengineering.cms.api.type.MutableCollectionDataType;
import com.smartitengineering.cms.api.type.MutableCompositeDataType;
import com.smartitengineering.cms.api.type.MutableContentCoProcessorDef;
import com.smartitengineering.cms.api.type.MutableContentDataType;
import com.smartitengineering.cms.api.type.MutableContentStatus;
import com.smartitengineering.cms.api.type.MutableContentType;
import com.smartitengineering.cms.api.type.MutableContentTypeId;
import com.smartitengineering.cms.api.type.MutableEnumDataType;
import com.smartitengineering.cms.api.type.MutableFieldDef;
import com.smartitengineering.cms.api.type.MutableOtherDataType;
import com.smartitengineering.cms.api.type.MutableRepresentationDef;
import com.smartitengineering.cms.api.type.MutableSearchDef;
import com.smartitengineering.cms.api.type.MutableValidatorDef;
import com.smartitengineering.cms.api.type.MutableVariationDef;
import com.smartitengineering.cms.api.type.MutableResourceUri;
import com.smartitengineering.cms.api.type.MutableStringDataType;
import com.smartitengineering.cms.api.workspace.WorkspaceId;
import com.smartitengineering.cms.spi.SmartContentSPI;
import com.smartitengineering.cms.spi.type.ContentTypeDefinitionParser;
import com.smartitengineering.cms.spi.type.PersistableContentType;
import com.smartitengineering.cms.spi.type.TypeValidator;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.time.DateFormatUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
*
* @author kaisar
*/
public class ContentTypeLoaderImpl implements ContentTypeLoader {
private final transient Logger logger = LoggerFactory.getLogger(getClass());
@Override
public ContentType loadContentType(ContentTypeId contentTypeID) throws NullPointerException {
final Collection<? extends ContentType> reads =
SmartContentSPI.getInstance().getContentTypeReader().
readContentTypeFromPersistentStorage(
contentTypeID);
if (reads.size() > 0) {
return reads.iterator().next();
}
else {
return null;
}
}
@Override
public Collection<WritableContentType> parseContentTypes(WorkspaceId workspaceId,
InputStream contentTypeDefinitionStream, MediaType mediaType)
throws NullPointerException, InvalidReferenceException, IOException {
TypeValidator validator = SmartContentSPI.getInstance().getTypeValidators().getValidators().get(mediaType);
ContentTypeDefinitionParser parser = SmartContentSPI.getInstance().getContentTypeDefinitionParsers().getParsers().
get(mediaType);
if (validator == null || parser == null) {
throw new IOException("Media type " + mediaType.toString() + " is not supported!");
}
if (!contentTypeDefinitionStream.markSupported()) {
contentTypeDefinitionStream = new BufferedInputStream(contentTypeDefinitionStream);
}
try {
if (!validator.isValid(contentTypeDefinitionStream)) {
throw new IOException("Content does not meet definition!");
}
final Collection<WritableContentType> types = parser.parseStream(workspaceId, contentTypeDefinitionStream);
if (logger.isDebugEnabled()) {
for (WritableContentType contentType : types) {
logger.debug("ID " + contentType.getContentTypeID());
}
}
List<ContentTypeImpl> resultingTypes = mergeWithStoredContentTypes(types);
return Collections.<WritableContentType>unmodifiableCollection(resultingTypes);
}
catch (InvalidReferenceException ex) {
throw ex;
}
catch (Exception ex) {
throw new IOException(ex);
}
}
protected List<ContentTypeImpl> mergeWithStoredContentTypes(final Collection<WritableContentType> types) throws
IllegalArgumentException {
final List<ContentTypeImpl> resultingTypes =
new ArrayList<ContentTypeImpl>(types.size());
final Collection<? extends ContentType> storedContentTypes;
final ContentTypeId[] ids = new ContentTypeId[types.size()];
int i = 0;
for (ContentType type : types) {
ids[i++] = type.getContentTypeID();
}
storedContentTypes =
SmartContentSPI.getInstance().getContentTypeReader().readContentTypeFromPersistentStorage(ids);
for (ContentType type : storedContentTypes) {
final ContentTypeImpl contentTypeImpl = getContentTypeImpl(type);
contentTypeImpl.setFromPersistentStorage(true);
resultingTypes.add(contentTypeImpl);
}
if (logger.isDebugEnabled()) {
logger.debug(new StringBuilder("After getting from persistent storage size is of 2b ReturnedList is ").append(resultingTypes.
size()).toString());
}
for (MutableContentType type : types) {
if (logger.isDebugEnabled()) {
logger.debug(new StringBuilder("Type ID is ").append(type.getContentTypeID()).toString());
}
int index = resultingTypes.indexOf(type);
if (index >= 0) {
logger.debug("Just merging");
final ContentTypeImpl get = resultingTypes.get(index);
merge(get, type);
get.setFromPersistentStorage(true);
}
else {
logger.debug("Adding to list");
resultingTypes.add(getContentTypeImpl(type));
}
}
return resultingTypes;
}
@Override
public MutableContentDataType getMutableContentDataType(ContentDataType contentDataType) {
if (contentDataType.getTypeDef() != null) {
ContentDataTypeImpl contentDataTypeImpl = new ContentDataTypeImpl();
contentDataTypeImpl.setTypeDef(contentDataType.getTypeDef());
contentDataTypeImpl.setBiBidirectionalFieldName(contentDataType.getBidirectionalFieldName());
return contentDataTypeImpl;
}
else {
throw new IllegalArgumentException("Argument can not be null.");
}
}
@Override
public MutableCollectionDataType getMutableCollectionDataType(CollectionDataType collectionDataType) {
if (collectionDataType.getItemDataType() != null && collectionDataType.getMinSize() >= 0 && collectionDataType.
getMaxSize() >= collectionDataType.getMinSize()) {
CollectionDataTypeImpl collectionDataTypeImpl = new CollectionDataTypeImpl();
collectionDataTypeImpl.setItemDataType(collectionDataType.getItemDataType());
collectionDataTypeImpl.setMaxSize(collectionDataType.getMaxSize());
collectionDataTypeImpl.setMinSize(collectionDataType.getMinSize());
return collectionDataTypeImpl;
}
else {
throw new IllegalArgumentException("Argument can not be null or min size has to be non-negative or max size can" +
" not be smaller than min zie.");
}
}
@Override
public MutableContentStatus getMutableContentStatus(ContentStatus contentStatus) {
ContentStatusImpl contentStatusImpl = new ContentStatusImpl();
contentStatusImpl.setContentTypeID(contentStatus.getContentType());
contentStatusImpl.setId(contentStatus.getId());
contentStatusImpl.setName(contentStatus.getName());
return contentStatusImpl;
}
@Override
public MutableContentTypeId getMutableContentTypeID(ContentTypeId contentTypeID) {
ContentTypeIdImpl contentTypeIdImpl = new ContentTypeIdImpl();
contentTypeIdImpl.setName(contentTypeID.getName());
contentTypeIdImpl.setNamespace(contentTypeID.getNamespace());
contentTypeIdImpl.setWorkspace(contentTypeID.getWorkspace());
return contentTypeIdImpl;
}
@Override
public MutableFieldDef getMutableFieldDef(FieldDef fieldDef) {
if (fieldDef != null) {
FieldDefImpl fieldDefImpl = new FieldDefImpl();
fieldDefImpl.setName(fieldDef.getName());
fieldDefImpl.setSearchDefinition(fieldDef.getSearchDefinition());
fieldDefImpl.setValueDef(fieldDef.getValueDef());
fieldDefImpl.setVariations(fieldDef.getVariations().values());
fieldDefImpl.setFieldStandaloneUpdateAble(true);
fieldDefImpl.setRequired(true);
return fieldDefImpl;
}
else {
throw new IllegalArgumentException("Argument can not be null.");
}
}
@Override
public MutableCollectionDataType createMutableCollectionDataType() {
return new CollectionDataTypeImpl();
}
@Override
public MutableContentDataType createMutableContentDataType() {
return new ContentDataTypeImpl();
}
@Override
public MutableContentStatus createMutableContentStatus() {
return new ContentStatusImpl();
}
@Override
public MutableContentTypeId createMutableContentTypeID() {
return new ContentTypeIdImpl();
}
@Override
public MutableFieldDef createMutableFieldDef(FieldDef parentContainer) {
final FieldDefImpl fieldDefImpl = new FieldDefImpl();
fieldDefImpl.setParentContainer(parentContainer);
return fieldDefImpl;
}
@Override
public MutableFieldDef createMutableFieldDef() {
return createMutableFieldDef(null);
}
@Override
public ContentTypeId createContentTypeId(WorkspaceId workspaceId, String namespace, String name) {
if (workspaceId != null && StringUtils.isNotBlank(namespace) && StringUtils.isNotBlank(name)) {
ContentTypeIdImpl contentTypeIdImpl = new ContentTypeIdImpl();
contentTypeIdImpl.setName(name);
contentTypeIdImpl.setNamespace(namespace);
contentTypeIdImpl.setWorkspace(workspaceId);
return contentTypeIdImpl;
}
else {
throw new IllegalArgumentException("Any of arguments can not be null or blank.");
}
}
@Override
public MutableContentType getMutableContentType(ContentType contentType) {
if (contentType != null) {
return getContentTypeImpl(contentType);
}
else {
throw new IllegalArgumentException("Argument can not be null.");
}
}
protected ContentTypeImpl getContentTypeImpl(ContentType contentType) throws IllegalArgumentException {
ContentTypeImpl typeImpl = new ContentTypeImpl();
merge(typeImpl, contentType);
return typeImpl;
}
protected void merge(ContentTypeImpl typeImpl, ContentType contentType) throws IllegalArgumentException {
typeImpl.setContentTypeID(contentType.getContentTypeID());
typeImpl.setCreationDate(contentType.getCreationDate());
typeImpl.setPrimaryFieldName(contentType.getPrimaryFieldName());
typeImpl.setDisplayName(contentType.getDisplayName());
typeImpl.setFromPersistentStorage(contentType instanceof PersistableContentType ?
((PersistableContentType) contentType).isFromPersistentStorage() : false);
typeImpl.setLastModifiedDate(contentType.getLastModifiedDate());
typeImpl.setEntityTagValue(contentType.getEntityTagValue());
typeImpl.setParent(contentType.getParent());
typeImpl.getMutableFieldDefs().clear();
typeImpl.getMutableFieldDefs().addAll(contentType.getOwnFieldDefs().values());
typeImpl.getMutableRepresentationDefs().clear();
typeImpl.getMutableRepresentationDefs().addAll(contentType.getRepresentationDefs().values());
typeImpl.getMutableStatuses().clear();
typeImpl.getMutableStatuses().addAll(contentType.getStatuses().values());
typeImpl.setRepresentations(contentType.getRepresentations());
typeImpl.setParameterizedDisplayNames(contentType.getParameterizedDisplayNames());
typeImpl.setDefinitionType(contentType.getSelfDefinitionType());
for (Collection<ContentCoProcessorDef> defs : contentType.getContentCoProcessorDefs().values()) {
for (ContentCoProcessorDef def : defs) {
typeImpl.addContentCoProcessorDef(def);
}
}
}
@Override
public MutableRepresentationDef createMutableRepresentationDef() {
return new RepresentationDefImpl();
}
@Override
public MutableVariationDef createMutableVariationDef() {
return new VariationDefImpl();
}
@Override
public MutableValidatorDef createMutableValidatorDef() {
return new ValidatorDefImpl();
}
@Override
public MutableResourceUri createMutableResourceUri() {
return new ResourceUriImpl();
}
@Override
public MutableSearchDef createMutableSearchDef() {
return new SearchDefImpl();
}
@Override
public MutableOtherDataType createMutableOtherDataType() {
return new OtherDataTypeImpl();
}
@Override
public MutableStringDataType createMutableStringDataType() {
return new StringDataTypeImpl();
}
@Override
public String getSearchFieldName(FieldDef fieldDef) {
return SmartContentSPI.getInstance().getSearchFieldNameGenerator().getSearchFieldName(fieldDef);
}
public String getSearchFieldNameWithoutTypeSpecifics(FieldDef fieldDef) {
return SmartContentSPI.getInstance().getSearchFieldNameGenerator().getFieldName(fieldDef);
}
@Override
public WritableContentType getWritableContentType(ContentType contentType) {
return getContentTypeImpl(contentType);
}
@Override
public String getEntityTagValueForContentType(ContentType contentType) {
return DigestUtils.md5Hex(new StringBuilder(DateFormatUtils.ISO_DATETIME_TIME_ZONE_FORMAT.format(contentType.
getLastModifiedDate())).append('~').append(contentType.getRepresentations().get(MediaType.APPLICATION_XML)).
toString());
}
@Override
public void reIndexTypes(WorkspaceId workspaceId) {
SmartContentSPI.getInstance().getContentTypeSearcher().reIndex(workspaceId);
}
@Override
public void reIndexType(ContentTypeId contentTypeId) {
SmartContentSPI.getInstance().getContentTypeSearcher().reIndex(contentTypeId);
}
@Override
public Filter createFilter() {
return new FilterImpl();
}
@Override
public SearchResult<ContentType> createSearchResult(Collection<ContentType> result, long totalResultsCount) {
SearchResultImpl<ContentType> resultImpl = new SearchResultImpl<ContentType>();
resultImpl.setResult(result);
resultImpl.setTotalResultsCount(totalResultsCount);
return resultImpl;
}
@Override
public SearchResult<ContentType> search(Filter filter) {
return SmartContentSPI.getInstance().getContentTypeSearcher().search(filter);
}
public MutableCompositeDataType createMutableCompositeDataType() {
return new CompositionDataTypeImpl();
}
public MutableCompositeDataType createMutableCompositeDataType(CompositeDataType dataType) {
CompositionDataTypeImpl dataTypeImpl = new CompositionDataTypeImpl();
if (dataType != null) {
dataTypeImpl.setEmbeddedContentDataType(dataType.getEmbeddedContentDataType());
dataTypeImpl.getOwnMutableComposition().addAll(dataType.getOwnComposition());
}
return dataTypeImpl;
}
public MutableEnumDataType createMutableEnumDataType() {
return new EnumDataTypeImpl();
}
public MutableEnumDataType createMutableEnumDataType(EnumDataType dataType) {
MutableEnumDataType type = createMutableEnumDataType();
if (dataType != null && dataType.getChoices() != null) {
type.setChoices(dataType.getChoices());
}
return type;
}
public MutableContentCoProcessorDef createMutableContentCoProcessorDef() {
return new ContentCoProcessorDefImpl();
}
}