001/*
002 *  Copyright 2021 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.duplicate.contents.attr;
017
018import java.util.HashSet;
019import java.util.Set;
020
021import org.apache.avalon.framework.configuration.Configuration;
022import org.apache.avalon.framework.configuration.ConfigurationException;
023
024import org.ametys.cms.search.query.AndQuery;
025import org.ametys.cms.search.query.NotQuery;
026import org.ametys.cms.search.query.Query;
027
028/**
029 * This abstract class represents a {@link DuplicateAttributeConfiguration}
030 * @param <T> The type of the attribute
031 */
032public abstract class AbstractDuplicateAttributeConfiguration<T> implements DuplicateAttributeConfiguration<T>
033{
034    
035    /** The component role. */
036    public static final String ROLE = AbstractDuplicateAttributeConfiguration.class.getName();
037
038    /** The type of the attribute. */
039    protected String _type;
040
041    /** The path of the attribute. */
042    protected String _path;
043
044    /** Defines this attribute should also check for near duplicates. */
045    protected boolean _checkNearDuplicate;
046
047    /**
048     * Create a new DuplicateAttributeConfiguration
049     * @param configuration the configuration used to create the DuplicateAttributeConfiguration
050     * @param attributeType the attribute type id
051     * @throws ConfigurationException if the configuration is not valid.
052     */
053    public AbstractDuplicateAttributeConfiguration(Configuration configuration, String attributeType) throws ConfigurationException
054    {
055        _path = configuration.getAttribute("path");
056        _checkNearDuplicate = _computeCheckNearDuplicate(configuration);
057        _type = attributeType;
058    }
059
060    /**
061     * Check if this attribute should also check for near duplicates
062     * @param configuration the configuration used to create the DuplicateAttributeConfiguration
063     * @return true if this attribute should also check for near duplicates
064     */
065    protected boolean _computeCheckNearDuplicate(Configuration configuration)
066    {
067        return false;
068    }
069
070    @Override
071    public String getType()
072    {
073        return _type;
074    }
075
076    @Override
077    public void setType(String type)
078    {
079        this._type = type;
080    }
081
082    @Override
083    public String getPath()
084    {
085        return _path;
086    }
087
088    @Override
089    public void setPath(String path)
090    {
091        this._path = path;
092    }
093
094    @Override
095    public boolean checkNearDuplicate()
096    {
097        return _checkNearDuplicate;
098    }
099
100    /**
101     * Get the query to check if a field is filled
102     * @return the query
103     */
104    protected abstract Query getExistQuery();
105
106    /**
107     * Get the query to check if other contents have the same value
108     * @param value the value to check
109     * @return the query
110     */
111    protected abstract Query getDuplicateQuery(T value);
112
113    /**
114     * Get the query to check if other contents have almost the same value
115     * @param value the value to check
116     * @return the query
117     */
118    protected Query getNearDuplicateQuery(T value)
119    {
120        return getDuplicateQuery(value);
121    }
122
123    /**
124     * Get the query to find duplicate of this attributes
125     * @param value the value of the attribute
126     * @param nearDuplicateQuery true if the query should check near duplicates
127     * @return the query to find duplicate of this attributes
128     */
129    protected Query getDuplicate(T value, boolean nearDuplicateQuery)
130    {
131        return nearDuplicateQuery ? getNearDuplicateQuery(value) : getDuplicateQuery(value);
132    }
133
134    @Override
135    @SuppressWarnings("unchecked")
136    public Query getQuery(Object value, boolean nearDuplicateQuery)
137    {
138        if (value == null || isEmpty(value))
139        {
140            return new NotQuery(getExistQuery());
141        }
142        
143        Class<?> type = value.getClass();
144        if (type.isArray())
145        {
146            if (((T[]) value).length == 0)
147            {
148                return new NotQuery(getExistQuery());
149            }
150            
151            Set<Query> queries = new HashSet<>();
152            for (T typedValue : (T[]) value)
153            {
154                queries.add(getDuplicate(typedValue, nearDuplicateQuery));
155            }
156            return new AndQuery(queries);
157        }
158        
159        return getDuplicate((T) value, nearDuplicateQuery);
160    }
161
162    /**
163     * Check if the value is empty
164     * @param value the value
165     * @return true if the value is empty
166     */
167    protected boolean isEmpty(Object value)
168    {
169        return false;
170    }
171}