001/*
002 *  Copyright 2011 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.odfweb;
017
018import java.net.URI;
019import java.util.Arrays;
020
021import org.apache.avalon.framework.context.Context;
022import org.apache.avalon.framework.context.ContextException;
023import org.apache.avalon.framework.context.Contextualizable;
024import org.apache.avalon.framework.service.ServiceException;
025import org.apache.avalon.framework.service.ServiceManager;
026import org.apache.cocoon.components.ContextHelper;
027import org.apache.cocoon.environment.Request;
028
029import org.ametys.cms.repository.Content;
030import org.ametys.cms.transformation.URIResolver;
031import org.ametys.core.util.URIUtils;
032import org.ametys.odf.ProgramItem;
033import org.ametys.odf.course.Course;
034import org.ametys.odf.program.AbstractProgram;
035import org.ametys.odf.program.Program;
036import org.ametys.odf.program.SubProgram;
037import org.ametys.plugins.odfweb.repository.OdfPageResolver;
038import org.ametys.runtime.config.Config;
039import org.ametys.web.URIPrefixHandler;
040import org.ametys.web.content.GetSiteAction;
041import org.ametys.web.renderingcontext.RenderingContext;
042import org.ametys.web.renderingcontext.RenderingContextHandler;
043import org.ametys.web.repository.page.Page;
044import org.ametys.web.repository.site.SiteManager;
045
046/**
047 * {@link URIResolver} for a ODF Content.
048 */
049public class OdfURIResolver extends org.ametys.odf.OdfURIResolver implements Contextualizable
050{
051    private Context _context;
052
053    private SiteManager _siteManager;
054
055    private OdfPageResolver _odfPageResolver;
056
057    private RenderingContextHandler _renderingContextHandler;
058
059    private URIPrefixHandler _prefixHandler;
060
061    @Override
062    public void service(ServiceManager manager) throws ServiceException
063    {
064        super.service(manager);
065        _odfPageResolver = (OdfPageResolver) manager.lookup(OdfPageResolver.ROLE);
066        _renderingContextHandler = (RenderingContextHandler) manager.lookup(RenderingContextHandler.ROLE);
067        _prefixHandler = (URIPrefixHandler) manager.lookup(URIPrefixHandler.ROLE);
068        _siteManager = (SiteManager) manager.lookup(SiteManager.ROLE);
069    }
070
071    @Override
072    public void contextualize(Context context) throws ContextException
073    {
074        _context = context;
075    }
076    
077    @Override
078    public String resolve(String uri, boolean download, boolean absolute, boolean internal)
079    {
080        Request request = ContextHelper.getRequest(_context);
081        String currentSite = (String) request.getAttribute(GetSiteAction.OVERRIDE_SITE_REQUEST_ATTR);
082        if (currentSite == null)
083        {
084            currentSite = (String) request.getAttribute("site");
085        }
086        if (currentSite == null)
087        {
088            currentSite = (String) request.getAttribute("siteName");
089        }
090
091        // Handle URI like content://UUID or
092        // courseContent://UUID;programContent://UUID or
093        // courseContent://UUID;courseContent://UUID;programContent://UUID
094        int i = uri.indexOf(';');
095        String contentId = uri;
096        if (i != -1)
097        {
098            contentId = uri.substring(0, i);
099        }
100
101        Content content = _resolver.resolveById(contentId);
102
103        Page odfRootPage = _odfPageResolver.getOdfRootPage(currentSite, content.getLanguage(), ((ProgramItem) content).getCatalog());
104
105        RenderingContext context = _renderingContextHandler.getRenderingContext();
106
107        Page page = null;
108
109        if (content instanceof Program)
110        {
111            page = _odfPageResolver.getProgramPage((Program) content, odfRootPage.getSiteName());
112        }
113        else if (content instanceof SubProgram)
114        {
115            page = _getSubProgramPage((SubProgram) content, odfRootPage, uri.split(";"));
116        }
117        else if (content instanceof Course)
118        {
119            page = _getCoursePage((Course) content, odfRootPage, uri.split(";"));
120        }
121        
122        if (page == null)
123        {
124            // No page found, back to content URI
125            String siteName = Config.getInstance().getValue("odf.web.site.name");
126            return _getContentURI(content, siteName, context, absolute, internal);
127        }
128
129        // We resolved a page either in the current site or in the ODF default site.
130        // The site is the page's site.
131        String siteName = page.getSiteName();
132        String pagePath = page.getSitemapName() + "/" + page.getPathInSitemap() + ".html";
133
134        try
135        {
136            if (!siteName.equals(currentSite) && context == RenderingContext.FRONT)
137            {
138                String url = _siteManager.getSite(siteName).getUrl();
139                return url + "/" + pagePath;
140            }
141
142            if (!(context == RenderingContext.BACK))
143            {
144                StringBuilder result = new StringBuilder();
145
146                if (internal)
147                {
148                    result.append("cocoon://").append(siteName);
149                }
150                else if (absolute)
151                {
152                    result.append(_prefixHandler.getAbsoluteUriPrefix(siteName));
153                }
154                else
155                {
156                    result.append(_prefixHandler.getUriPrefix(siteName));
157                }
158
159                result.append("/").append(pagePath);
160                
161                return URIUtils.encodePath(result.toString());
162            }
163            else // back
164            {
165                return "javascript:(function(){parent.Ametys.tool.ToolsManager.openTool('uitool-page', {id:'" + page.getId() + "'});})()";
166            }
167        }
168        catch (Exception e)
169        {
170            throw new IllegalStateException(e);
171        }
172    }
173    
174    private Page _getSubProgramPage(SubProgram subProgram, Page odfRootPage, String[] paths)
175    {
176        if (odfRootPage == null)
177        {
178            // There is no ODF root page
179            return null;
180        }
181
182        if (paths.length > 2)
183        {
184            // Possible paths are :
185            // [subProgramContent://UUID1, programContent://UUID1]
186            // [subProgramContent://UUID1, subProgramContent://UUID1]
187            // [subprogramContent://UUID, subprogramContent://UUID, subprogramContent://UUID]
188            // [subprogramContent://UUID, subprogramContent://UUID, programContent://UUID]
189
190            return _odfPageResolver.getSubProgramPage(odfRootPage, subProgram, Arrays.asList(paths).reversed(), true);
191        }
192        else
193        {
194            // [subProgramContent://UUID1]
195            return _odfPageResolver.getSubProgramPage(odfRootPage, subProgram, null);
196        }
197    }
198
199    private Page _getCoursePage(Course course, Page odfRootPage, String[] paths)
200    {
201        if (odfRootPage == null)
202        {
203            // There is no ODF root page
204            return null;
205        }
206        
207        if (paths.length >= 2)
208        {
209            // Possible paths are :
210            // [courseContent://UUID1, courseContent://UUID1]
211            // [courseContent://UUID1, programContent://UUID1]
212            // [courseContent://UUID1, subProgramContent://UUID1]
213            // [courseContent://UUID1, courseContent://UUID2, ..., courseContent://UUID3, (sub)programContent://UUID]
214            // [courseContent://UUID1, courseContent://UUID2, ..., courseContent://UUID3]
215            // [courseContent://UUID1, subprogramContent://UUID2, ..., (sub)programContent://UUID3]
216
217            return _odfPageResolver.getCoursePage(odfRootPage, course, Arrays.asList(paths).subList(1, paths.length).reversed(), true);
218        }
219        else
220        {
221            // [courseContent://UUID1]
222            return _odfPageResolver.getCoursePage(odfRootPage, course, (AbstractProgram) null);
223        }
224    }
225
226    /**
227     * Get the content URI
228     * 
229     * @param content The content
230     * @param siteName The site name
231     * @param context The rendering context
232     * @param absolute true if the url must be absolute
233     * @param internal true to get an internal URI.
234     * @return the content URI
235     */
236    protected String _getContentURI(Content content, String siteName, RenderingContext context, boolean absolute, boolean internal)
237    {
238        try
239        {
240            if (context == RenderingContext.FRONT)
241            {
242                // In FO mode do not give the content URI
243                return "";
244            }
245            else if (!(context == RenderingContext.BACK))
246            {
247                StringBuilder result = new StringBuilder();
248
249                if (internal)
250                {
251                    result.append("cocoon://").append(siteName);
252                }
253                else if (absolute)
254                {
255                    result.append(_prefixHandler.getAbsoluteUriPrefix());
256                }
257                else
258                {
259                    result.append(_prefixHandler.getUriPrefix());
260                }
261                result.append("/").append("_wrapped-content.html");
262                String query = "contentId=" + content.getId() + "&userLocale=" + content.getLanguage() + "&siteName=" + siteName;
263                return new URI(null, null, result.toString(), query, null).toASCIIString();
264            }
265            else
266            {
267                return "javascript:(function(){parent.Ametys.tool.ToolsManager.openTool('uitool-content', {id:'" + content.getId() + "'});})()";
268            }
269        }
270        catch (Exception e)
271        {
272            throw new IllegalStateException(e);
273        }
274    }
275}