001/*
002 *  Copyright 2013 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.workspaces.query;
017
018import java.io.IOException;
019import java.util.HashMap;
020import java.util.Map;
021
022import org.apache.avalon.framework.parameters.Parameters;
023import org.apache.avalon.framework.service.ServiceException;
024import org.apache.avalon.framework.service.ServiceManager;
025import org.apache.cocoon.acting.ServiceableAction;
026import org.apache.cocoon.environment.ObjectModelHelper;
027import org.apache.cocoon.environment.Redirector;
028import org.apache.cocoon.environment.Request;
029import org.apache.cocoon.environment.SourceResolver;
030import org.apache.commons.lang.ArrayUtils;
031import org.apache.commons.lang3.StringUtils;
032import org.apache.excalibur.source.Source;
033
034import org.ametys.cms.search.cocoon.SearchGenerator;
035import org.ametys.core.authentication.AuthenticateAction;
036import org.ametys.core.user.CurrentUserProvider;
037import org.ametys.core.user.UserIdentity;
038import org.ametys.core.util.JSONUtils;
039import org.ametys.plugins.queriesdirectory.Query;
040import org.ametys.plugins.queriesdirectory.QueryDAO;
041import org.ametys.plugins.repository.AmetysObjectResolver;
042import org.ametys.runtime.authentication.AccessDeniedException;
043
044/**
045 * Get query parameters from query
046 *
047 */
048public class GetQueryParametersAction extends ServiceableAction
049{
050    
051    private static final String _XSLT_BASE_LOCATION = "context://WEB-INF/stylesheets/export";
052    
053    private AmetysObjectResolver _resolver;
054
055    /** The Json utils */
056    private JSONUtils _jsonUtils;
057
058    private CurrentUserProvider _currentUserProvide;
059
060    private QueryDAO _queryDAO;
061    
062    @Override
063    public void service(ServiceManager smanager) throws ServiceException
064    {
065        super.service(smanager);
066        _resolver = (AmetysObjectResolver) smanager.lookup(AmetysObjectResolver.ROLE);
067        _jsonUtils = (JSONUtils) smanager.lookup(JSONUtils.ROLE);
068        _currentUserProvide = (CurrentUserProvider) smanager.lookup(CurrentUserProvider.ROLE);
069        _queryDAO = (QueryDAO) smanager.lookup(QueryDAO.ROLE);
070    }
071
072    @Override
073    public Map act(Redirector redirector, SourceResolver resolver, Map objectModel, String source, Parameters parameters) throws Exception
074    {
075        Map<String, String> result = new HashMap<>();
076        Request request = ObjectModelHelper.getRequest(objectModel);
077
078        request.setAttribute(AuthenticateAction.REQUEST_ATTRIBUTE_INTERNAL_ALLOWED, true);
079        
080        String queryId = request.getParameter("queryId");
081        String xslt = parameters.getParameter("xslt", "");
082        
083        UserIdentity user = _currentUserProvide.getUser();
084
085        Query query = _resolver.resolveById(queryId);
086        
087        if (!_queryDAO.canRead(user, query))
088        {
089            throw new AccessDeniedException("The user " + user + " is not allowed to access the query with id " + queryId);
090        }
091        
092        String xsltFile = StringUtils.defaultString(getXsltLocation(resolver, xslt));
093        
094        Map<String, Object> content = _jsonUtils.convertJsonToMap(query.getContent());
095        @SuppressWarnings("unchecked")
096        Map<String, Object> params = (Map<String, Object>) content.get("exportParams");
097        
098        String versionLabel = parameters.getParameter("versionLabel");
099        if (StringUtils.isNotBlank(versionLabel))
100        {
101            params.put(SearchGenerator.CONTENT_VERSION_LABEL, versionLabel);
102        }
103        
104        String pluginName = (String) content.get("exportXMLUrlPlugin");
105        String exportUrl = (String) content.get("exportXMLUrl");
106
107        result.put("pluginName", pluginName != null ? pluginName : "cms");
108        result.put("exportUrl", exportUrl != null ? exportUrl : "search/export.xml");
109        
110        result.put("parameters", InternalEncoder.encode(_jsonUtils.convertObjectToJson(params)));
111        result.put("xsltFile", xsltFile);
112        return result;
113    }
114    
115    /**
116     * Get the XSLT location.
117     * @param resolver the source resolver.
118     * @param xslt the requested xslt.
119     * @return the XSLT file location.
120     * @throws IOException if an error occurs resolving the XSLT.
121     */
122    protected String getXsltLocation(SourceResolver resolver, String xslt) throws IOException
123    {
124        Source xsltSource = null;
125        try
126        {
127            if (StringUtils.isNotBlank(xslt))
128            {
129                String location = _XSLT_BASE_LOCATION + "/" + xslt;
130                xsltSource = resolver.resolveURI(location);
131                
132                if (xsltSource.exists())
133                {
134                    return location;
135                }
136            }
137        }
138        finally
139        {
140            if (xsltSource != null)
141            {
142                resolver.release(xsltSource);
143            }
144        }
145        
146        return null;
147    }
148    
149    /**
150     * Helper defining methods used to partially encode the query string of
151     * internal (cocoon) wrapped requests.
152     */
153    private static final class InternalEncoder
154    {
155        private static final char[] NEED_ENCODING = {'%', '&', '=', '?', ' ', '+'};
156
157        private InternalEncoder()
158        {
159            // Do not instantiate
160        }
161        
162        /**
163         * Partially encode a string given the NEED_ENCODING array.
164         * @param str The string to encode
165         * @return encode String.
166         */
167        public static String encode(String str)
168        {
169            boolean changed = false;
170            final char escape = '%';
171            
172            int len = str.length();
173            StringBuilder sb = new StringBuilder(len);
174            
175            for (int i = 0; i < len; i++)
176            {
177                char ch = str.charAt(i);
178                if (ArrayUtils.contains(NEED_ENCODING, ch))
179                {
180                    sb.append(escape);
181                    sb.append(Integer.toHexString(ch));
182                    changed = true;
183                }
184                else
185                {
186                    sb.append(ch);
187                }
188            }
189            
190            return changed ? sb.toString() : str;
191        }
192    }
193}
194