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.Iterator;
020import java.util.LinkedHashMap;
021import java.util.LinkedList;
022import java.util.List;
023import java.util.Map;
024
025import org.apache.avalon.framework.parameters.Parameters;
026import org.apache.avalon.framework.service.ServiceException;
027import org.apache.avalon.framework.service.ServiceManager;
028import org.apache.cocoon.acting.ServiceableAction;
029import org.apache.cocoon.environment.ObjectModelHelper;
030import org.apache.cocoon.environment.Redirector;
031import org.apache.cocoon.environment.Request;
032import org.apache.cocoon.environment.SourceResolver;
033import org.slf4j.Logger;
034import org.slf4j.LoggerFactory;
035
036import org.ametys.core.cocoon.JSonReader;
037import org.ametys.core.util.JSONUtils;
038import org.ametys.core.util.ServerCommHelper;
039import org.ametys.plugins.contentio.synchronize.SynchronizableContentsCollection;
040import org.ametys.plugins.contentio.synchronize.SynchronizableContentsCollectionDAO;
041
042/**
043 * Action to search in a SCC.
044 */
045public class SCCSearchAction extends ServiceableAction
046{
047    /** Field imported to display in SCCSearchTool */
048    protected static final String FIELD_IMPORTED = "imported";
049    
050    /** SCC DAO */
051    protected SynchronizableContentsCollectionDAO _synchronizableContentsCollectionDAO;
052    /** ServerComm Helper */
053    protected ServerCommHelper _serverCommHelper;
054    /** JSON Utils */
055    protected JSONUtils _jsonUtils;
056    
057    private Logger _logger = LoggerFactory.getLogger(SCCSearchAction.class);
058    
059    @Override
060    public void service(ServiceManager smanager) throws ServiceException
061    {
062        super.service(smanager);
063        _synchronizableContentsCollectionDAO = (SynchronizableContentsCollectionDAO) smanager.lookup(SynchronizableContentsCollectionDAO.ROLE);
064        _serverCommHelper = (ServerCommHelper) smanager.lookup(ServerCommHelper.ROLE);
065        _jsonUtils = (JSONUtils) smanager.lookup(JSONUtils.ROLE);
066    }
067
068    @SuppressWarnings("unchecked")
069    @Override
070    public Map act(Redirector redirector, SourceResolver resolver, Map objectModel, String source, Parameters parameters) throws Exception
071    {
072        // Get JS parameters
073        Map<String, Object> jsParameters = _serverCommHelper.getJsParameters();
074        
075        // Mask imported
076        Map<String, Object> searchParams = (Map<String, Object>) jsParameters.get("values");
077        boolean maskImported = searchParams.containsKey(SCCSearchModelConfiguration.CRITERIA_MASK_IMPORTED) && Boolean.valueOf(searchParams.get(SCCSearchModelConfiguration.CRITERIA_MASK_IMPORTED).toString());
078        searchParams.remove(SCCSearchModelConfiguration.CRITERIA_MASK_IMPORTED);
079        
080        // Get the collection for search
081        String collectionId = (String) jsParameters.get("collectionId");
082        SynchronizableContentsCollection collection = _synchronizableContentsCollectionDAO.getSynchronizableContentsCollection(collectionId);
083        
084        // Search
085        Integer offset = _getIntValue(jsParameters, "start", 0);
086        Integer limit = _getIntValue(jsParameters, "limit", Integer.MAX_VALUE);
087
088        // Construct the JSON object
089        Map<String, Object> objectToRead = new HashMap<>();
090        
091        // Different treatment if we need to mask imported or not (one is optimized)
092        if (maskImported)
093        {
094            Map<String, Map<String, Object>> results = collection.search(searchParams, 0, Integer.MAX_VALUE, _getSortList(jsParameters.get("sort")), _logger);
095            Iterator<String> resultKeys = results.keySet().iterator();
096            
097            // Skip offset
098            int currentOffset = 0;
099            while (currentOffset < offset && resultKeys.hasNext())
100            {
101                if (collection.getContent(null, resultKeys.next(), true) == null)
102                {
103                    currentOffset++;
104                }
105            }
106            
107            // Get the contents to the limit
108            List<Map<String, Object>> finalResults = new LinkedList<>();
109            int currentLimit = 0;
110            while (currentLimit < limit && resultKeys.hasNext())
111            {
112                String idValue = resultKeys.next();
113                Map<String, Object> contentResults = new HashMap<>(results.get(idValue));
114                if (collection.getContent(null, idValue, true) == null)
115                {
116                    // Add to results
117                    contentResults.put(FIELD_IMPORTED, false);
118                    finalResults.add(contentResults);
119                    currentLimit++;
120                }
121            }
122            
123            objectToRead.put("items", finalResults);
124            // FIXME CONTENTIO-87
125            objectToRead.put("total", collection.getTotalCount(searchParams, _logger));
126        }
127        else
128        {
129            Map<String, Map<String, Object>> results = new LinkedHashMap<>(collection.search(searchParams, offset, limit, _getSortList(jsParameters.get("sort")), _logger));
130
131            for (String idValue : results.keySet())
132            {
133                Map<String, Object> contentResults = new HashMap<>(results.get(idValue));
134                contentResults.put(FIELD_IMPORTED, collection.getContent(null, idValue, true) != null);
135                results.put(idValue, contentResults);
136            }
137            
138            objectToRead.put("items", results.values());
139            objectToRead.put("total", collection.getTotalCount(searchParams, _logger));
140        }
141        
142        // Add JSON to the request to be parsed
143        Request request = ObjectModelHelper.getRequest(objectModel);
144        request.setAttribute(JSonReader.OBJECT_TO_READ, objectToRead);
145        
146        return EMPTY_MAP;
147    }
148    
149    private int _getIntValue(Map<String, Object> values, String key, int defaultValue)
150    {
151        if (values.containsKey(key))
152        {
153            return Integer.valueOf(values.get(key).toString()).intValue();
154        }
155        
156        return defaultValue;
157    }
158    
159    private List<Object> _getSortList(Object sortValues)
160    {
161        if (sortValues != null)
162        {
163            return _jsonUtils.convertJsonToList(sortValues.toString());
164        }
165        
166        return null;
167    }
168}