001/*
002 *  Copyright 2017 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.plugins.contentio.synchronize.search;
017
018import java.util.HashMap;
019import java.util.HashSet;
020import java.util.List;
021import java.util.Locale;
022import java.util.Map;
023import java.util.Set;
024
025import org.apache.avalon.framework.component.Component;
026import org.apache.avalon.framework.service.ServiceException;
027import org.apache.avalon.framework.service.ServiceManager;
028import org.apache.avalon.framework.service.Serviceable;
029import org.apache.commons.lang3.LocaleUtils;
030import org.apache.commons.lang3.StringUtils;
031
032import org.ametys.cms.repository.Content;
033import org.ametys.cms.repository.ModifiableContent;
034import org.ametys.core.ui.Callable;
035import org.ametys.plugins.contentio.synchronize.SynchronizableContentsCollection;
036import org.ametys.plugins.contentio.synchronize.SynchronizableContentsCollectionDAO;
037import org.ametys.plugins.repository.AmetysObjectResolver;
038import org.ametys.runtime.plugin.component.AbstractLogEnabled;
039
040import com.google.common.collect.ImmutableList;
041import com.google.common.collect.ImmutableMap;
042
043/**
044 * Helper for SCC callables.
045 */
046public class SCCSearchToolHelper extends AbstractLogEnabled implements Component, Serviceable
047{
048    /** SCC DAO */
049    protected SynchronizableContentsCollectionDAO _synchronizableContentsCollectionDAO;
050    
051    /** The Ametys resolver */
052    protected AmetysObjectResolver _resolver;
053
054    @Override
055    public void service(ServiceManager manager) throws ServiceException
056    {
057        _synchronizableContentsCollectionDAO = (SynchronizableContentsCollectionDAO) manager.lookup(SynchronizableContentsCollectionDAO.ROLE);
058        _resolver = (AmetysObjectResolver) manager.lookup(AmetysObjectResolver.ROLE);
059    }
060
061    /**
062     * Get the {@link SCCSearchModelConfiguration} from the collectionId.
063     * @param collectionId Collection ID
064     * @return The {@link SCCSearchModelConfiguration}
065     */
066    @Callable
067    public Map<String, Object> getSearchModelConfiguration(String collectionId)
068    {
069        SynchronizableContentsCollection collection = _synchronizableContentsCollectionDAO.getSynchronizableContentsCollection(collectionId);
070        SCCSearchModelConfiguration searchModelConfiguration = collection.getSearchModelConfiguration();
071        return searchModelConfiguration.toJSON();
072    }
073
074    /**
075     * Import the content specified by the id in the specified collection.
076     * @param collectionId Collection ID
077     * @param id Synchonization ID of the content
078     * @param additionalParameters Additional parameters
079     * @return Imported contents
080     */
081    @Callable
082    public Map<String, Object> importContent(String collectionId, String id, Map<String, Object> additionalParameters)
083    {
084        if (StringUtils.isBlank(id))
085        {
086            getLogger().warn("The synchronization code cannot be empty.");
087            return Map.of("error", "noSyncCode");
088        }
089        
090        Map<String, Object> result = new HashMap<>();
091        
092        try
093        {
094            Locale defaultLocale = additionalParameters.containsKey("language") ? LocaleUtils.toLocale((String) additionalParameters.get("language")) : null;
095            Set<Map<String, String>> contentsList = new HashSet<>();
096            
097            SynchronizableContentsCollection collection = _synchronizableContentsCollectionDAO.getSynchronizableContentsCollection(collectionId);
098            Content existingContent = collection.getContent(null, id, true);
099            if (existingContent == null)
100            {
101                List<ModifiableContent> contents = collection.importContent(id, additionalParameters, getLogger());
102                for (ModifiableContent content : contents)
103                {
104                    Map<String, String> contentMap = new HashMap<>();
105                    contentMap.put("id", content.getId());
106                    contentMap.put("title", content.getTitle(defaultLocale));
107                    contentMap.put("lang", content.getLanguage());
108                    contentsList.add(contentMap);
109                }
110                result.put("contents", contentsList);
111                result.put("total", contents.size());
112            }
113            else
114            {
115                result.put("contents", ImmutableList.of(ImmutableMap.of("id", existingContent.getId(), "title", existingContent.getTitle(defaultLocale), "lang", existingContent.getLanguage())));
116                result.put("error", "alreadyImported");
117            }
118        }
119        catch (Exception e)
120        {
121            String errorMessage = "An exception occured during import of the content '" + id + "' on SCC '" + collectionId + "'";
122            getLogger().error(errorMessage, e);
123            throw new IllegalStateException(errorMessage);
124        }
125        
126        return result;
127    }
128    
129    /**
130     * Synchronize the content on the given collection with the given synchronization code.
131     * @param collectionId Collection ID
132     * @param contentId Content ID
133     * @param syncCode Synchronization code
134     * @return true if an error occured
135     */
136    @Callable
137    public boolean synchronizeContent(String collectionId, String contentId, String syncCode)
138    {
139        ModifiableContent content = _resolver.resolveById(contentId);
140        boolean hasErrors = false;
141        
142        try
143        {
144            SynchronizableContentsCollection collection = _synchronizableContentsCollectionDAO.getSynchronizableContentsCollection(collectionId);
145            
146            // First, add, update or remove synchronization informations
147            collection.updateSyncInformations(content, syncCode, getLogger());
148            
149            // If the synchronization code is empty, the process ends here
150            if (StringUtils.isBlank(syncCode))
151            {
152                return false;
153            }
154            
155            Map<String, Object> searchParameters = new HashMap<>();
156            searchParameters.put(collection.getIdField(), syncCode);
157            
158            if (collection.getTotalCount(searchParameters, getLogger()) > 0)
159            {
160                collection.synchronizeContent(content, getLogger());
161            }
162            else
163            {
164                getLogger().warn("In the collection '{}', there is not content matching with the synchronization code '{}'.", collectionId, syncCode);
165                hasErrors = true;
166            }
167        }
168        catch (Exception e)
169        {
170            getLogger().error("An error occured while synchronizing the content '{}' with the synchronization code '{}' from the '{}' collection.", contentId, syncCode, collectionId, e);
171            hasErrors = true;
172        }
173        
174        return hasErrors;
175    }
176    
177    /**
178     * Get the value of the synchronization field.
179     * @param collectionId Collection ID
180     * @param contentId Content ID
181     * @return The value of the synchronization field
182     */
183    @Callable
184    public String getSyncCode(String contentId, String collectionId)
185    {
186        SynchronizableContentsCollection collection = _synchronizableContentsCollectionDAO.getSynchronizableContentsCollection(collectionId);
187        Content content = _resolver.resolveById(contentId);
188        
189        String syncCode = null;
190        if (content.hasValue(collection.getIdField()))
191        {
192            syncCode = content.getValue(collection.getIdField());
193        }
194        return syncCode;
195    }
196}