001/*
002 *  Copyright 2015 Anyware Services
003 *
004 *  Licensed under the Apache License, Version 2.0 (the "License");
005 *  you may not use this file except in compliance with the License.
006 *  You may obtain a copy of the License at
007 *
008 *      http://www.apache.org/licenses/LICENSE-2.0
009 *
010 *  Unless required by applicable law or agreed to in writing, software
011 *  distributed under the License is distributed on an "AS IS" BASIS,
012 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 *  See the License for the specific language governing permissions and
014 *  limitations under the License.
015 */
016package org.ametys.cms.contenttype.indexing;
017
018import java.util.ArrayList;
019import java.util.Collection;
020import java.util.Collections;
021import java.util.List;
022
023import org.ametys.cms.contenttype.ContentConstants;
024import org.ametys.cms.contenttype.ContentType;
025import org.ametys.cms.contenttype.MetadataDefinition;
026import org.ametys.cms.contenttype.MetadataDefinitionHolder;
027import org.ametys.cms.contenttype.MetadataType;
028import org.ametys.cms.contenttype.RepeaterDefinition;
029import org.ametys.cms.contenttype.SemanticAnnotation;
030import org.ametys.cms.repository.Content;
031import org.ametys.plugins.repository.metadata.CompositeMetadata;
032import org.ametys.plugins.repository.metadata.RichText;
033import org.ametys.plugins.repository.metadata.UnknownMetadataException;
034import org.ametys.runtime.i18n.I18nizableText;
035
036/**
037 * IndexingField realizing the indexation of semantic annotations.
038 */
039public class SemanticAnnotationIndexingField implements CustomIndexingField
040{
041    
042    private static final String __ANNOTATION_PREFIX = "annotation-";
043    
044    /** The referenced semantic annotation. */
045    protected SemanticAnnotation _annotation;
046    
047    /** The metadata paths. */
048    protected List<String> _metaPaths;
049    
050    /** The declaring content type. */
051    protected ContentType _contentType;
052    
053    /**
054     * Build a SemanticAnnotationIndexingField.
055     * @param annotation The semantic annotation.
056     * @param metaPaths The paths of the rich text metadatas declaring the annotation.
057     * @param contentType The declaring content type.
058     */
059    public SemanticAnnotationIndexingField(SemanticAnnotation annotation, Collection<String> metaPaths, ContentType contentType)
060    {
061        _annotation = annotation;
062        _metaPaths = new ArrayList<>(metaPaths);
063        _contentType = contentType;
064    }
065    
066    @Override
067    public String getName()
068    {
069        return __ANNOTATION_PREFIX + _annotation.getId();
070    }
071    
072    @Override
073    public I18nizableText getLabel()
074    {
075        return _annotation.getLabel();
076    }
077    
078    @Override
079    public I18nizableText getDescription()
080    {
081        return _annotation.getDescription();
082    }
083    
084    @Override
085    public MetadataType getType()
086    {
087        return MetadataType.STRING;
088    }
089    
090    @Override
091    public Object[] getValues(Content content)
092    {
093        List<String> values = new ArrayList<>();
094        
095        for (String metaPath : _metaPaths)
096        {
097            addAnnotationValues(values, content.getMetadataHolder(), _contentType, metaPath);
098        }
099        
100        return values.toArray(new String[values.size()]);
101    }
102    
103    /**
104     * Add the annotation values from a given rich text to the global value list.
105     * @param values The global value list to fill.
106     * @param metaHolder The current metadata holder.
107     * @param metaDefHolder The current metadata definition holder.
108     * @param metaPath The metadata path from the current metadata holder.
109     */
110    private void addAnnotationValues(List<String> values, CompositeMetadata metaHolder, MetadataDefinitionHolder metaDefHolder, String metaPath)
111    {
112        try
113        {
114            int slashPos = metaPath.indexOf(ContentConstants.METADATA_PATH_SEPARATOR);
115            
116            if (slashPos == -1)
117            {
118                // Last component of the path: get the annotation values from the rich text.
119                addAnnotationValues(values, metaHolder.getRichText(metaPath));
120            }
121            else
122            {
123                // Intermediary component of the metadata tree.
124                String metaName = metaPath.substring(0, slashPos);
125                String remainingPath = metaPath.substring(slashPos + 1);
126                MetadataDefinition compositeDef = metaDefHolder.getMetadataDefinition(metaName);
127                CompositeMetadata composite = metaHolder.getCompositeMetadata(metaName);
128                
129                if (compositeDef instanceof RepeaterDefinition)
130                {
131                    // The current metadata is a repeater: get the values from each entry.
132                    for (String entryName : composite.getMetadataNames())
133                    {
134                        CompositeMetadata entry = composite.getCompositeMetadata(entryName);
135                        addAnnotationValues(values, entry, compositeDef, remainingPath);
136                    }
137                }
138                else
139                {
140                    // The current metadata is a repeater: get the values from each entry.
141                    addAnnotationValues(values, composite, compositeDef, remainingPath);
142                }
143            }
144        }
145        catch (UnknownMetadataException e)
146        {
147            // Ignore, just don't add values.
148        }
149    }
150    
151    /**
152     * Add the annotation values from a given rich text to the global value list.
153     * @param allValues The global value list to fill.
154     * @param richText The rich text.
155     */
156    private void addAnnotationValues(List<String> allValues, RichText richText)
157    {
158        if (richText != null)
159        {
160            String[] values = richText.getAnnotationValues(_annotation.getId());
161            Collections.addAll(allValues, values);
162        }
163    }
164
165}