/* * * 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.spi.impl.content.search; import com.google.inject.Inject; import com.smartitengineering.cms.api.content.CollectionFieldValue; import com.smartitengineering.cms.api.content.CompositeFieldValue; import com.smartitengineering.cms.api.content.Content; import com.smartitengineering.cms.api.content.ContentId; import com.smartitengineering.cms.api.content.Field; import com.smartitengineering.cms.api.content.FieldValue; import com.smartitengineering.cms.api.factory.SmartContentAPI; import com.smartitengineering.cms.api.type.CollectionDataType; import com.smartitengineering.cms.api.type.ContentDataType; import com.smartitengineering.cms.api.type.ContentType; import com.smartitengineering.cms.api.type.ContentTypeId; import com.smartitengineering.cms.api.type.DataType; import com.smartitengineering.cms.api.type.FieldDef; import com.smartitengineering.cms.api.type.FieldValueType; import com.smartitengineering.cms.spi.SmartContentSPI; import com.smartitengineering.cms.spi.impl.SearchBeanLoader; import com.smartitengineering.cms.spi.impl.events.SolrFieldNames; import com.smartitengineering.dao.solr.MultivalueMap; import com.smartitengineering.dao.solr.impl.MultivalueMapImpl; import com.smartitengineering.util.bean.adapter.AbstractAdapterHelper; import java.util.Collection; import java.util.HashSet; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import org.apache.commons.codec.binary.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * * @author imyousuf */ public class ContentHelper extends AbstractAdapterHelper<Content, MultivalueMap<String, Object>> { protected static final String CONTENT = "content"; @Inject private SearchBeanLoader<Content, ContentId> contentLoader; private final transient Logger logger = LoggerFactory.getLogger(getClass()); @Override protected MultivalueMap<String, Object> newTInstance() { return new MultivalueMapImpl<String, Object>(); } @Override protected void mergeFromF2T(Content fromBean, MultivalueMap<String, Object> toBean) { toBean.addValue(SolrFieldNames.TYPE, CONTENT); final ContentId id = fromBean.getContentId(); toBean.addValue(SolrFieldNames.ID, id.toString()); toBean.addValue(SolrFieldNames.WORKSPACEID, id.getWorkspaceId().toString()); final Content mutableContent = fromBean; toBean.addValue(SolrFieldNames.CREATIONDATE, mutableContent.getCreationDate()); toBean.addValue(SolrFieldNames.LASTMODIFIEDDATE, mutableContent.getLastModifiedDate()); toBean.addValue(SolrFieldNames.STATUS, mutableContent.getStatus().getName()); final String typeIdString = mutableContent.getContentDefinition().getContentTypeID().toString(); toBean.addValue(SolrFieldNames.CONTENTTYPEID, typeIdString); toBean.addValue(SolrFieldNames.PRIVATE, mutableContent.isPrivate()); toBean.addValue(SolrFieldNames.INSTANCE_OF, typeIdString); //Content is a instance of all it parent types ContentType contentType = mutableContent.getContentDefinition(); ContentTypeId parent = contentType.getParent(); while (parent != null) { toBean.addValue(SolrFieldNames.INSTANCE_OF, parent.toString()); final ContentType partentType = SmartContentAPI.getInstance().getContentTypeLoader().loadContentType(parent); parent = partentType.getParent(); } Set<ContentId> indexedContents = new HashSet<ContentId>(); indexFields(mutableContent, toBean, "", indexedContents, '_'); } protected void indexFields(final Content mutableContent, MultivalueMap<String, Object> toBean, final String prefix, Set<ContentId> indexedContents, final char separator) { if (logger.isDebugEnabled()) { logger.debug("Indexing contents with prefix " + prefix + " and separator " + separator); } if (indexedContents.contains(mutableContent.getContentId())) { return; } indexedContents.add(mutableContent.getContentId()); Map<String, Field> fields = mutableContent.getFields(); indexFields(fields, prefix, separator, toBean, indexedContents); } protected void indexFields(Map<String, Field> fields, final String prefix, final char separator, MultivalueMap<String, Object> toBean, Set<ContentId> indexedContents) { if (logger.isDebugEnabled()) { logger.debug("Indexing fields" + fields + " with prefix " + prefix + " and separator " + separator); } for (Entry<String, Field> entry : fields.entrySet()) { FieldDef def = entry.getValue().getFieldDef(); if (logger.isDebugEnabled()) { logger.debug("Field Def " + def.getName() + " available for search: " + def.getSearchDefinition()); } if (def.getSearchDefinition() == null) { continue; } Field field = entry.getValue(); StringBuilder builder = new StringBuilder(); if (org.apache.commons.lang.StringUtils.isNotBlank(prefix)) { builder.append(prefix).append(separator); } String defName = SmartContentSPI.getInstance().getSearchFieldNameGenerator().getSearchFieldName(def); if (org.apache.commons.lang.StringUtils.isBlank(defName)) { continue; } String searchFieldName = builder.append(defName).toString(); if (logger.isDebugEnabled()) { logger.debug("Search field name " + searchFieldName); } if (org.apache.commons.lang.StringUtils.isNotBlank(searchFieldName)) { addFieldValue(toBean, searchFieldName, field, prefix, indexedContents, '_'); } } } protected void addFieldValue(MultivalueMap<String, Object> toBean, String indexFieldName, Field field, final String prefix, Set<ContentId> indexedContents, final char separator) { if (logger.isDebugEnabled()) { logger.debug("Indexing field value " + field.getName() + " with prefix " + prefix + " and separator " + separator); } if (field == null || field.getValue() == null || field.getValue().getValue() == null) { return; } final Object value = field.getValue().getValue(); addSimpleValue(field.getValue(), field.getFieldDef().getValueDef(), toBean, field.getFieldDef(), indexFieldName, value, prefix, '_', indexedContents); } protected void addSimpleValue(final FieldValue def, DataType fieldDataType, MultivalueMap<String, Object> toBean, FieldDef fieldDef, String indexFieldName, final Object value, final String prefix, final char separator, Set<ContentId> indexedContents) { if (logger.isDebugEnabled()) { logger.debug("Indexing simple value " + fieldDataType.getType() + " with prefix " + prefix + " and separator " + separator); } final FieldValueType valueDef = def.getDataType(); switch (valueDef) { case COMPOSITE: { CompositeFieldValue compositeFieldValue = (CompositeFieldValue) def; indexFields(compositeFieldValue.getValueAsMap(), prefix, separator, toBean, indexedContents); break; } case COLLECTION: CollectionFieldValue fieldValue = (CollectionFieldValue) def; Collection<FieldValue> values = fieldValue.getValue(); for (FieldValue val : values) { addSimpleValue(val, ((CollectionDataType) fieldDataType).getItemDataType(), toBean, fieldDef, indexFieldName, val.getValue(), prefix, '_', indexedContents); } break; case CONTENT: toBean.addValue(indexFieldName, value.toString()); final ContentDataType contentDataType = (ContentDataType) fieldDataType; if (logger.isDebugEnabled()) { logger.debug("Nested Content " + contentDataType.getTypeDef().toString() + " available for search: " + contentDataType.isAvaialbleForSearch()); } if (contentDataType.isAvaialbleForSearch()) { Content content = SmartContentAPI.getInstance().getContentLoader().loadContent((ContentId) value); if (content != null) { StringBuilder newPrefix = new StringBuilder(); if (org.apache.commons.lang.StringUtils.isNotBlank(prefix)) { newPrefix.append(prefix).append(separator); } newPrefix.append(SmartContentSPI.getInstance().getSearchFieldNameGenerator().getFieldName(fieldDef)); indexFields(content, toBean, newPrefix.toString(), indexedContents, separator); } } break; default: toBean.addValue(indexFieldName, value); break; } } @Override protected Content convertFromT2F(MultivalueMap<String, Object> toBean) { try { byte[] contentId = StringUtils.getBytesUtf8(toBean.getFirst(SolrFieldNames.ID).toString()); ContentId id = contentLoader.getFromByteArray(contentId); return SmartContentAPI.getInstance().getContentLoader().loadContent(id); } catch (Exception ex) { logger.error("Error converting to content, returning null!", ex); } return null; } }