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