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;
019
020import org.apache.avalon.framework.context.Context;
021import org.apache.avalon.framework.context.ContextException;
022import org.apache.avalon.framework.context.Contextualizable;
023import org.apache.avalon.framework.service.ServiceException;
024import org.apache.avalon.framework.service.ServiceManager;
025import org.apache.cocoon.components.ContextHelper;
026import org.apache.cocoon.environment.Request;
027
028import org.ametys.cms.repository.Content;
029import org.ametys.cms.transformation.URIResolver;
030import org.ametys.core.util.URIUtils;
031import org.ametys.odf.ProgramItem;
032import org.ametys.odf.course.Course;
033import org.ametys.odf.program.AbstractProgram;
034import org.ametys.odf.program.Program;
035import org.ametys.odf.program.SubProgram;
036import org.ametys.plugins.odfweb.repository.OdfPageHandler;
037import org.ametys.plugins.odfweb.repository.OdfPageResolver;
038import org.ametys.plugins.repository.AmetysObject;
039import org.ametys.runtime.config.Config;
040import org.ametys.web.URIPrefixHandler;
041import org.ametys.web.content.GetSiteAction;
042import org.ametys.web.renderingcontext.RenderingContext;
043import org.ametys.web.renderingcontext.RenderingContextHandler;
044import org.ametys.web.repository.page.Page;
045import org.ametys.web.repository.site.SiteManager;
046
047/**
048 * {@link URIResolver} for a ODF Content.
049 */
050public class OdfURIResolver extends org.ametys.odf.OdfURIResolver implements Contextualizable
051{
052    private Context _context;
053
054    private SiteManager _siteManager;
055
056    private OdfPageResolver _odfPageResolver;
057
058    private RenderingContextHandler _renderingContextHandler;
059
060    private URIPrefixHandler _prefixHandler;
061
062    private OdfPageHandler _odfPageHandler;
063
064    @Override
065    public void service(ServiceManager manager) throws ServiceException
066    {
067        super.service(manager);
068        _odfPageResolver = (OdfPageResolver) manager.lookup(OdfPageResolver.ROLE);
069        _odfPageHandler = (OdfPageHandler) manager.lookup(OdfPageHandler.ROLE);
070        _renderingContextHandler = (RenderingContextHandler) manager.lookup(RenderingContextHandler.ROLE);
071        _prefixHandler = (URIPrefixHandler) manager.lookup(URIPrefixHandler.ROLE);
072        _siteManager = (SiteManager) manager.lookup(SiteManager.ROLE);
073    }
074
075    @Override
076    public void contextualize(Context context) throws ContextException
077    {
078        _context = context;
079    }
080
081    @Override
082    public String resolve(String uri, boolean download, boolean absolute, boolean internal)
083    {
084        Request request = ContextHelper.getRequest(_context);
085        String currentSite = (String) request.getAttribute(GetSiteAction.OVERRIDE_SITE_REQUEST_ATTR);
086        if (currentSite == null)
087        {
088            currentSite = (String) request.getAttribute("site");
089        }
090        if (currentSite == null)
091        {
092            currentSite = (String) request.getAttribute("siteName");
093        }
094
095        // Handle URI like content://UUID or
096        // courseContent://UUID;programContent://UUID or
097        // courseContent://UUID;courseContent://UUID;programContent://UUID
098        int i = uri.indexOf(';');
099        String contentId = uri;
100        if (i != -1)
101        {
102            contentId = uri.substring(0, i);
103        }
104
105        Content content = _resolver.resolveById(contentId);
106
107        Page odfRootPage = _odfPageResolver.getOdfRootPage(currentSite, content.getLanguage(), ((ProgramItem) content).getCatalog());
108
109        RenderingContext context = _renderingContextHandler.getRenderingContext();
110
111        Page page = null;
112        String pagePath = null;
113
114        if (content instanceof Program)
115        {
116            page = _odfPageResolver.getProgramPage((Program) content, currentSite);
117        }
118        else if (content instanceof SubProgram)
119        {
120            page = _getSubProgramPage((SubProgram) content, odfRootPage, uri.split(";"));
121        }
122        else if (content instanceof Course)
123        {
124            page = _getCoursePage((Course) content, odfRootPage, uri.split(";"));
125        }
126
127        if (page == null)
128        {
129            // No page found, back to content URI
130            String siteName = Config.getInstance().getValue("odf.web.site.name");
131            return _getContentURI(content, siteName, context, absolute, internal);
132        }
133
134        // We resolved a page either in the current site or in the ODF default
135        // site.
136        // The site is the page's site.
137        String siteName = page.getSiteName();
138
139        pagePath = page.getSitemapName() + "/" + page.getPathInSitemap() + ".html";
140
141        try
142        {
143            if (!siteName.equals(currentSite) && context == RenderingContext.FRONT)
144            {
145                String url = _siteManager.getSite(siteName).getUrl();
146                return url + "/" + page.getSitemapName() + "/" + page.getPathInSitemap() + ".html";
147            }
148
149            if (!(context == RenderingContext.BACK))
150            {
151                StringBuilder result = new StringBuilder();
152
153                if (internal)
154                {
155                    result.append("cocoon://").append(siteName);
156                }
157                else if (absolute)
158                {
159                    result.append(_prefixHandler.getAbsoluteUriPrefix(siteName));
160                }
161                else
162                {
163                    result.append(_prefixHandler.getUriPrefix(siteName));
164                }
165
166                result.append("/").append(pagePath);
167                
168                return URIUtils.encodePath(result.toString());
169            }
170            else // back
171            {
172                return "javascript:(function(){parent.Ametys.tool.ToolsManager.openTool('uitool-page', {id:'" + page.getId() + "'});})()";
173            }
174        }
175        catch (Exception e)
176        {
177            throw new IllegalStateException(e);
178        }
179    }
180
181    private Page _getSubProgramPage(SubProgram subProgram, Page odfRootPage, String[] paths)
182    {
183        if (odfRootPage == null)
184        {
185            // There is no ODF root page
186            return null;
187        }
188
189        int index = paths.length - 1;
190        if (paths.length > 2)
191        {
192            // Possible paths are :
193            // [subprogramContent://UUID, subprogramContent://UUID,
194            // subprogramContent://UUID]
195            // [subprogramContent://UUID, subprogramContent://UUID,
196            // programContent://UUID]
197
198            AmetysObject lastParent = _resolver.resolveById(paths[index]);
199
200            Program rootProgram = null;
201            if (lastParent instanceof Program)
202            {
203                rootProgram = (Program) lastParent;
204            }
205            else
206            {
207                rootProgram = _odfPageResolver.getParentProgram((ProgramItem) lastParent, null);
208            }
209
210            if (rootProgram == null)
211            {
212                return null;
213            }
214
215            String pagePath = _odfPageResolver.getPathInProgram((ProgramItem) lastParent, null);
216            index -= 1;
217
218            while (index > 0)
219            {
220                ProgramItem parentItem = _resolver.resolveById(paths[index]);
221                if (parentItem instanceof AbstractProgram)
222                {
223                    pagePath += '/' + _odfPageHandler.getPageName(parentItem);
224                    index--;
225                }
226            }
227
228            return _resolver.resolveById("program://" + pagePath + "?rootId=" + odfRootPage.getId() + "&programId=" + subProgram.getId() + "&parentId=" + rootProgram.getId());
229        }
230        else if (paths.length == 2)
231        {
232            // Possible paths are :
233            // [subProgramContent://UUID1, programContent://UUID1]
234            // [subProgramContent://UUID1, subProgramContent://UUID1]
235
236            AmetysObject parent = _resolver.resolveById(paths[index]);
237            if (parent instanceof AbstractProgram)
238            {
239                return _odfPageResolver.getSubProgramPage(odfRootPage, subProgram, (AbstractProgram) parent);
240            }
241        }
242        else
243        {
244            // [subProgramContent://UUID1]
245            return _odfPageResolver.getSubProgramPage(odfRootPage, subProgram, null);
246        }
247
248        // No page found
249        return null;
250    }
251
252    private Page _getCoursePage(Course course, Page odfRootPage, String[] paths)
253    {
254        if (odfRootPage == null)
255        {
256            // There is no ODF root page
257            return null;
258        }
259
260        int index = paths.length - 1;
261        if (paths.length > 2)
262        {
263            // Possible paths are :
264            // [courseContent://UUID1, courseContent://UUID2, ..., courseContent://UUID3, (sub)programContent://UUID]
265            // [courseContent://UUID1, courseContent://UUID2, ..., courseContent://UUID3]
266            // [courseContent://UUID1, subprogramContent://UUID2, ..., (sub)programContent://UUID3]
267
268            AmetysObject lastParent = _resolver.resolveById(paths[index]);
269
270            Program rootProgram = null;
271            if (lastParent instanceof Program)
272            {
273                rootProgram = (Program) lastParent;
274            }
275            else
276            {
277                rootProgram = _odfPageResolver.getParentProgram((ProgramItem) lastParent, null);
278            }
279
280            if (rootProgram == null)
281            {
282                return null;
283            }
284
285            String pagePath = _odfPageResolver.getPathInProgram((ProgramItem) lastParent, null);
286            index -= 1;
287
288            while (index > 0)
289            {
290                ProgramItem parentItem = _resolver.resolveById(paths[index]);
291                if (parentItem instanceof AbstractProgram || parentItem instanceof Course)
292                {
293                    pagePath += '/' + _odfPageHandler.getPageName(parentItem);
294                    index--;
295                }
296            }
297
298            return _resolver.resolveById("course://" + pagePath + "?rootId=" + odfRootPage.getId() + "&courseId=" + course.getId() + "&programId=" + rootProgram.getId());
299        }
300        else if (paths.length == 2)
301        {
302            // Possible paths are :
303            // [courseContent://UUID1, courseContent://UUID1]
304            // [courseContent://UUID1, programContent://UUID1]
305            // [courseContent://UUID1, subProgramContent://UUID1]
306
307            AmetysObject parent = _resolver.resolveById(paths[index]);
308            if (parent instanceof AbstractProgram)
309            {
310                return _odfPageResolver.getCoursePage(odfRootPage, course, (AbstractProgram) parent);
311            }
312            else if (parent instanceof Course)
313            {
314                return _odfPageResolver.getCoursePage(odfRootPage, course, (Course) parent);
315            }
316        }
317        else
318        {
319            // [courseContent://UUID1]
320            return _odfPageResolver.getCoursePage(odfRootPage, course, (AbstractProgram) null);
321        }
322
323        // No page found
324        return null;
325    }
326
327    /**
328     * Get the content URI
329     * 
330     * @param content The content
331     * @param siteName The site name
332     * @param context The rendering context
333     * @param absolute true if the url must be absolute
334     * @param internal true to get an internal URI.
335     * @return the content URI
336     */
337    protected String _getContentURI(Content content, String siteName, RenderingContext context, boolean absolute, boolean internal)
338    {
339        try
340        {
341            if (context == RenderingContext.FRONT)
342            {
343                // In FO mode do not give the content URI
344                return "";
345            }
346            else if (!(context == RenderingContext.BACK))
347            {
348                StringBuilder result = new StringBuilder();
349
350                if (internal)
351                {
352                    result.append("cocoon://").append(siteName);
353                }
354                else if (absolute)
355                {
356                    result.append(_prefixHandler.getAbsoluteUriPrefix());
357                }
358                else
359                {
360                    result.append(_prefixHandler.getUriPrefix());
361                }
362                result.append("/").append("_wrapped-content.html");
363                String query = "contentId=" + content.getId() + "&userLocale=" + content.getLanguage() + "&siteName=" + siteName;
364                return new URI(null, null, result.toString(), query, null).toASCIIString();
365            }
366            else
367            {
368                return "javascript:(function(){parent.Ametys.tool.ToolsManager.openTool('uitool-content', {id:'" + content.getId() + "'});})()";
369            }
370        }
371        catch (Exception e)
372        {
373            throw new IllegalStateException(e);
374        }
375    }
376}