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