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 */
016
017package org.ametys.plugins.odfweb.repository;
018
019import java.util.Map;
020
021import org.apache.commons.lang3.StringUtils;
022
023import org.ametys.odf.program.AbstractProgram;
024import org.ametys.odf.program.Program;
025import org.ametys.plugins.repository.AmetysObjectFactory;
026import org.ametys.plugins.repository.AmetysRepositoryException;
027import org.ametys.plugins.repository.UnknownAmetysObjectException;
028import org.ametys.web.repository.page.Page;
029
030import com.google.common.base.Splitter;
031
032/**
033 * {@link AmetysObjectFactory} handling {@link ProgramPage}.
034 */
035public class ProgramPageFactory extends AbstractOdfPageFactory implements AmetysObjectFactory<ProgramPage>
036{
037    /**
038     * Create a program page.
039     * @param root the ODF root page.
040     * @param program the program or subprogram.
041     * @param path The path from the virtual second level page. Can be null if abstract program is a {@link Program}
042     * @param parent the parent program in case of a subprogram, null otherwise
043     * @param parentPage the parent {@link Page} or null if not yet computed.
044     * @return The <code>ProgramPage</code> created
045     */
046    public ProgramPage createProgramPage(Page root, AbstractProgram program, String path, Program parent, Page parentPage) 
047    {
048        return new ProgramPage(root, getConfiguration(), this, program, path, parent, parentPage);
049    }
050    
051    @Override
052    public ProgramPage getAmetysObjectById(String id) throws AmetysRepositoryException
053    {
054        // Id is like program://_root?rootId=xxxx&programId=xxxx for Program
055        // Id is like program://path/to/subprogram?rootId=xxxx&programId=xxxx&parentId=xxxx for SubProgram
056        
057        String path = StringUtils.substringBetween(id, "://", "?");
058        String queryString = StringUtils.substringAfter(id, "?");
059        Map<String, String> ids = Splitter.on("&").withKeyValueSeparator("=").split(queryString);
060        
061        String rootId = ids.get("rootId");
062        String programId = ids.get("programId");
063        String parentId = ids.get("parentId");
064        
065        if ("_root".equals(path))
066        {
067            // Case of a program
068            path = null;
069        }
070        
071        Page root = _resolver.resolveById(rootId);
072        AbstractProgram program = _resolver.resolveById(programId); // program or subprogram
073        Program parent = StringUtils.isNotEmpty(parentId) ? _resolver.resolveById(parentId) : null;
074        Program parentProgramOrSelf = _getParentProgramOrSelf(parent, program);
075        
076        // The identifier is invalid
077        if (parentProgramOrSelf == null)
078        {
079            throw new UnknownAmetysObjectException("The object '" + program.getId() + "' is not a Program and its given parent is null.");
080        }
081        
082        // Test program restriction
083        if (!_odfPageHandler.isValidRestriction(root, parentProgramOrSelf))
084        {
085            throw new UnknownAmetysObjectException("There's no program child page " + programId + " for site " + root.getSiteName());
086        }
087        
088        try 
089        {
090            ProgramPage programPage = createProgramPage(root, program, path, parent, null);
091       
092            // Test if the virtual page really exists
093            programPage.getPathInSitemap();
094            
095            return programPage;
096        }
097        catch (UnknownAmetysObjectException e)
098        {
099            throw new UnknownAmetysObjectException("There's no program child page " + programId + " for site " + root.getSiteName(), e);
100        }
101    }
102    
103    private Program _getParentProgramOrSelf(Program parent, AbstractProgram self) throws UnknownAmetysObjectException
104    {
105        if (parent != null)
106        {
107            return parent;
108        }
109        
110        // In old identifiers, a subprogram target doesn't need the parentId, so if we don't have a parent, it can be an old target with a subprogram
111        if (self instanceof Program)
112        {
113            return (Program) self;
114        }
115        
116        return null;
117    }
118    
119    @Override
120    public String getScheme()
121    {
122        return "program";
123    }
124
125    @Override
126    public boolean hasAmetysObjectForId(String id) throws AmetysRepositoryException
127    {
128        int i = id.indexOf('?');
129            
130        String queryString = id.substring(i + 1);
131        Map<String, String> ids = Splitter.on("&").withKeyValueSeparator("=").split(queryString);
132        
133        String rootId = ids.get("rootId");
134        String programId = ids.get("programId");
135        String parentId = ids.get("parentId");
136        
137        if (!_resolver.hasAmetysObjectForId(rootId) || !_resolver.hasAmetysObjectForId(programId))
138        {
139            return false;
140        }
141        
142        Page root = _resolver.resolveById(rootId);
143        AbstractProgram program = _resolver.resolveById(programId); // program or subprogram
144        Program parent = StringUtils.isNotEmpty(parentId) ? _resolver.resolveById(parentId) : null;
145        Program parentProgramOrSelf = _getParentProgramOrSelf(parent, program);
146
147        // The identifier is invalid
148        if (parentProgramOrSelf == null)
149        {
150            return false;
151        }
152        
153        if (!_odfPageHandler.isValidRestriction(root, parentProgramOrSelf))
154        {
155            return false;
156        }
157        
158        if (StringUtils.isNotBlank(_odfPageHandler.getLevel2Metadata(root)))
159        {
160            return _odfPageHandler.getProgramLevel1Value(root, parentProgramOrSelf) != null && _odfPageHandler.getProgramLevel2Value(root, parentProgramOrSelf) != null;
161        }
162        else if (StringUtils.isNotBlank(_odfPageHandler.getLevel1Metadata(root)))
163        {
164            return _odfPageHandler.getProgramLevel1Value(root, parentProgramOrSelf) != null;
165        }
166        
167        return true;
168    }
169}