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