001/*
002 *  Copyright 2010 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.site;
017
018import java.util.HashMap;
019import java.util.Iterator;
020import java.util.List;
021import java.util.Map;
022
023import org.apache.avalon.framework.parameters.Parameters;
024import org.apache.avalon.framework.service.ServiceException;
025import org.apache.avalon.framework.thread.ThreadSafe;
026import org.apache.cocoon.acting.ServiceableAction;
027import org.apache.cocoon.environment.ObjectModelHelper;
028import org.apache.cocoon.environment.PermanentRedirector;
029import org.apache.cocoon.environment.Redirector;
030import org.apache.cocoon.environment.Request;
031import org.apache.cocoon.environment.Response;
032import org.apache.cocoon.environment.SourceResolver;
033import org.apache.commons.lang3.StringUtils;
034import org.apache.excalibur.source.SourceNotFoundException;
035
036import org.ametys.core.util.URIUtils;
037import org.ametys.plugins.site.Site;
038import org.ametys.plugins.site.SiteInformationCache;
039import org.ametys.plugins.site.SiteUrl;
040
041/**
042 * Get the site from server path, port and path.
043 */
044public class GetSiteAction extends ServiceableAction implements ThreadSafe
045{
046    /**
047     * sub_path in the uri to indicate the edition mode, and parameter passed to back
048     */
049    public static final String EDITION_URI = "edition";
050
051    private SiteInformationCache _siteCache;
052    
053    /**
054     * Get the site information cache
055     * @return the SiteInformationCache
056     */
057    protected SiteInformationCache _getSiteInformationCache()
058    {
059        if (_siteCache == null)
060        {
061            try
062            {
063                _siteCache = (SiteInformationCache) manager.lookup(SiteInformationCache.ROLE);
064            }
065            catch (ServiceException e)
066            {
067                throw new IllegalStateException("Cannot get SiteInformationCache", e);
068            }
069        }
070        return _siteCache;
071    }
072    
073    @Override
074    public Map act(Redirector redirector, SourceResolver resolver, Map objectModel, String source, Parameters parameters) throws Exception
075    {
076        Request request = ObjectModelHelper.getRequest(objectModel);
077        Response response = ObjectModelHelper.getResponse(objectModel);
078        
079        String frontServer = request.getServerName();
080        String frontPort = String.valueOf(request.getServerPort());
081        String frontPath = request.getRequestURI();
082        
083        frontPath = frontPath.endsWith("/") ? frontPath.substring(0, frontPath.length() - 1) : frontPath;
084
085        Map<SiteUrl, Site> sites = _getSiteInformationCache().getSites();
086        Iterator<SiteUrl> it = sites.keySet().iterator();
087        
088        Site result = null;
089        String pathInSite = null;
090        String path = null;
091        HashMap<String, String> map = new HashMap<>();
092
093        while (result == null && it.hasNext())
094        {
095            SiteUrl url = it.next();
096            Site site = sites.get(url);
097            String serverName = url.getServerName();
098            String port = url.getServerPort();
099            path = url.getServerPath();
100            path = path.endsWith("/") ? path.substring(0, path.length() - 1) : path;
101
102            if (serverName.equals(frontServer) && frontPort.equals(port) && frontPath.startsWith(path))
103            {
104                // same server and port, the path starts with the configured context, the current site is eligible
105                result = site;
106                pathInSite = frontPath.equals(path) ? "" : frontPath.substring(path.length() + 1);
107                
108                if (frontPath.equals(path) || "index.html".equals(pathInSite))
109                {
110                    // root was requested
111                    List<String> languages = site.getLanguages();
112                    
113                    String language = _findLanguage(request, languages);
114                    
115                    String redirectURI = url.getServerPath() + "/" + language + "/index.html";
116                    
117                    if (redirector instanceof PermanentRedirector)
118                    {
119                        ((PermanentRedirector) redirector).permanentRedirect(false, redirectURI);
120                        response.setHeader("Cache-Control", "no-cache");
121                    }
122                    else
123                    {
124                        redirector.redirect(false, redirectURI);
125                    }
126                    
127                    return null;
128                }
129
130                if (pathInSite.startsWith(EDITION_URI + "/"))
131                {
132                    url = new SiteUrl(url.getServerName(), url.getServerPort(), url.getServerPath() + "/" + EDITION_URI);
133                    path += "/" + EDITION_URI;
134                    pathInSite = pathInSite.substring(EDITION_URI.length() + 1);
135
136                    request.setAttribute(EDITION_URI, "true");
137                }
138                
139                // per spec, request.getRequestURI() is not decoded, so we have to do it here
140                pathInSite = URIUtils.decode(pathInSite);
141                
142                request.setAttribute("site", result);
143                request.setAttribute("url", url);
144                request.setAttribute("path", pathInSite);
145                request.setAttribute("requestedURI", request.getRequestURI());
146            }
147        }
148
149        if (result == null)
150        {
151            throw new SourceNotFoundException("There's no site registered in the cms for url http(s)://" + frontServer + ":" + frontPort + frontPath + "/");
152        }
153
154        map.put("site", result.getName());
155        map.put("path", pathInSite);
156        
157        String p = path;
158        p = StringUtils.removeStart(p, request.getContextPath());
159        p = StringUtils.removeStart(p, "/");
160        p = StringUtils.isBlank(p) ? "" : (p + "/");
161        map.put("sitePath", p);
162        request.setAttribute("sitePath", p);
163
164        return map;
165    }
166    
167    private String _findLanguage(Request request, List<String> availableLanguages)
168    {
169        String requestLanguage = request.getLocale().getLanguage();
170        
171        return availableLanguages.contains(requestLanguage) ? requestLanguage : availableLanguages.contains("en") ? "en" : availableLanguages.get(0);
172    }
173}