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.logger.AbstractLogEnabled;
027import org.apache.avalon.framework.service.ServiceException;
028import org.apache.avalon.framework.service.ServiceManager;
029import org.apache.avalon.framework.service.Serviceable;
030import org.slf4j.Logger;
031
032import org.ametys.cms.repository.Content;
033import org.ametys.cms.repository.ModifiableDefaultContent;
034import org.ametys.core.ui.Callable;
035import org.ametys.core.util.AvalonLoggerAdapter;
036import org.ametys.plugins.contentio.synchronize.SynchronizableContentsCollection;
037import org.ametys.plugins.contentio.synchronize.SynchronizableContentsCollectionDAO;
038import org.ametys.plugins.repository.AmetysObjectResolver;
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        Logger logger = new AvalonLoggerAdapter(getLogger());
085        
086        Map<String, Object> result = new HashMap<>();
087        
088        try
089        {
090            Locale defaultLocale = additionalParameters.containsKey("language") ? new Locale((String) additionalParameters.get("language")) : null;
091            Set<Map<String, String>> contentsList = new HashSet<>();
092            
093            SynchronizableContentsCollection collection = _synchronizableContentsCollectionDAO.getSynchronizableContentsCollection(collectionId);
094            Content existingContent = collection.getContent(null, id);
095            if (existingContent == null)
096            {
097                List<ModifiableDefaultContent> contents = collection.importContent(id, additionalParameters, logger);
098                for (ModifiableDefaultContent content : contents)
099                {
100                    Map<String, String> contentMap = new HashMap<>();
101                    contentMap.put("id", content.getId());
102                    contentMap.put("title", content.getTitle(defaultLocale));
103                    contentMap.put("lang", content.getLanguage());
104                    contentsList.add(contentMap);
105                }
106                result.put("contents", contentsList);
107                result.put("total", contents.size());
108            }
109            else
110            {
111                result.put("contents", ImmutableList.of(ImmutableMap.of("id", existingContent.getId(), "title", existingContent.getTitle(defaultLocale), "lang", existingContent.getLanguage())));
112                result.put("error", "alreadyImported");
113            }
114        }
115        catch (Exception e)
116        {
117            String errorMessage = "An exception occured during import of the content '" + id + "' on SCC '" + collectionId + "'";
118            logger.error(errorMessage, e);
119            throw new IllegalStateException(errorMessage);
120        }
121        
122        return result;
123    }
124    
125    /**
126     * Synchronize the content on the given collection with the given synchronization code.
127     * @param collectionId Collection ID
128     * @param contentId Content ID
129     * @param syncCode Synchronization code
130     * @return true if an error occured
131     */
132    @Callable
133    public boolean synchronizeContent(String collectionId, String contentId, String syncCode)
134    {
135        Logger logger = new AvalonLoggerAdapter(getLogger());
136        
137        ModifiableDefaultContent content = _resolver.resolveById(contentId);
138        boolean hasErrors = false;
139        
140        try
141        {
142            SynchronizableContentsCollection collection = _synchronizableContentsCollectionDAO.getSynchronizableContentsCollection(collectionId);
143            
144            Map<String, Object> searchParameters = new HashMap<>();
145            searchParameters.put(collection.getIdField(), syncCode);
146            
147            if (collection.getTotalCount(searchParameters, logger) > 0)
148            {
149                collection.updateSyncInformations(content, syncCode, logger);
150                collection.synchronizeContent(content, logger);
151            }
152            else
153            {
154                logger.warn("In the collection '{}', there is not content matching with the synchronization code '{}'.", collectionId, syncCode);
155                hasErrors = true;
156            }
157        }
158        catch (Exception e)
159        {
160            logger.error("An error occured while synchronizing the content '{}' with the synchronization code '{}' from the '{}' collection.", contentId, syncCode, collectionId, e);
161            hasErrors = true;
162        }
163        
164        return hasErrors;
165    }
166    
167    /**
168     * Get the value of the synchronization field.
169     * @param collectionId Collection ID
170     * @param contentId Content ID
171     * @return The value of the synchronization field
172     */
173    @Callable
174    public String getSyncCode(String contentId, String collectionId)
175    {
176        SynchronizableContentsCollection collection = _synchronizableContentsCollectionDAO.getSynchronizableContentsCollection(collectionId);
177        Content content = _resolver.resolveById(contentId);
178        
179        String syncCode = null;
180        if (content.getMetadataHolder().hasMetadata(collection.getIdField()))
181        {
182            syncCode = content.getMetadataHolder().getString(collection.getIdField());
183        }
184        return syncCode;
185    }
186}