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