001/*
002 *  Copyright 2022 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.web.service;
017
018import java.io.IOException;
019import java.util.ArrayList;
020import java.util.HashMap;
021import java.util.List;
022import java.util.Map;
023
024import org.apache.avalon.framework.parameters.Parameters;
025import org.apache.avalon.framework.service.ServiceException;
026import org.apache.avalon.framework.service.ServiceManager;
027import org.apache.avalon.framework.service.Serviceable;
028import org.apache.cocoon.acting.AbstractAction;
029import org.apache.cocoon.environment.ObjectModelHelper;
030import org.apache.cocoon.environment.Redirector;
031import org.apache.cocoon.environment.Request;
032import org.apache.excalibur.source.Source;
033import org.apache.excalibur.source.SourceResolver;
034
035import org.ametys.web.WebConstants;
036import org.ametys.web.repository.page.ZoneItem;
037
038/**
039 * This action export the wrapping XSLT URI for a service.<br>
040 * Service negociation will be performed with the given URI: if service.xsl is asked, service-[serviceId].xsl will be looked up first.
041 * 
042 * This action needs the parameter <code>path</code> pointing the default path to the XSL.
043 */
044public class GetServiceWrapperContextAction extends AbstractAction implements Serviceable
045{
046    /** The source resolver */
047    protected SourceResolver _srcResolver;
048    
049    @Override
050    public void service(ServiceManager manager) throws ServiceException
051    {
052        _srcResolver = (SourceResolver) manager.lookup(SourceResolver.ROLE);
053    }
054    
055    @Override
056    public Map<String, String> act(Redirector redirector, org.apache.cocoon.environment.SourceResolver resolver, Map objectModel, String source, Parameters parameters) throws Exception
057    {
058        Request request = ObjectModelHelper.getRequest(objectModel);
059        
060        HashMap<String, String> result = new HashMap<>();
061        String uri = parameters.getParameter("path");
062        String wrapperURI = getWrapperURI(request, uri);
063        
064        result.put("wrapper-uri", wrapperURI);
065        return result;
066    }
067    
068    /**
069     * Compute the wrapping URI for the current service.
070     * @param request the current Request.
071     * @param uri the default uri.
072     * @return the wrapper XSLT URI.
073     * @throws IOException if an error occurs while resolving Sources.
074     */
075    protected String getWrapperURI(Request request, String uri) throws IOException
076    {
077        String wrapperURI = null;
078        
079        ZoneItem zoneItem = (ZoneItem) request.getAttribute(WebConstants.REQUEST_ATTR_ZONEITEM);
080        String serviceId = zoneItem.getServiceId();
081        
082        // Ex : skin://stylesheets/service/_wrapper/service-[serviceId].xsl
083        int index = uri.indexOf(".xsl");
084        wrapperURI = "skin://" + uri.substring(0, index) + "-" + serviceId + ".xsl";
085        Source src = _srcResolver.resolveURI(wrapperURI);
086        if (!src.exists())
087        {
088            if (getLogger().isDebugEnabled())
089            {
090                getLogger().debug("Failed to find a file in the skin for '" + wrapperURI + "'. Rollink back to skin protocol.");
091            }
092            
093            // Ex : skin://stylesheets/service/_wrapper/service.xsl
094            wrapperURI = "skin://" + uri;
095            src = _srcResolver.resolveURI(wrapperURI);
096            if (!src.exists())
097            {
098                if (getLogger().isDebugEnabled())
099                {
100                    getLogger().debug("Failed to find a file in the skin for '" + wrapperURI + "'. Rollink back to context protocol.");
101                }
102
103                wrapperURI = _getWrapperURIFromSources(request, uri);
104            }
105        }
106
107        return wrapperURI;
108    }
109    
110    /**
111     * Get wrapper URI from sources
112     * @param request the current Request.
113     * @param uri the default uri.
114     * @return the wrapper XSLT URI.
115     * @throws IOException if an error occurs while resolving Sources.
116     */
117    protected String _getWrapperURIFromSources(Request request, String uri) throws IOException
118    {
119        for (String wrapperURI : getSourceURIs(request, uri))
120        {
121            Source src = _srcResolver.resolveURI(wrapperURI);
122            if (!src.exists())
123            {
124                if (getLogger().isDebugEnabled())
125                {
126                    getLogger().debug("Failed to find a stylesheet at '" + wrapperURI + "'.");
127                }
128            }
129            else
130            {
131                return wrapperURI;
132            }
133        }
134        
135        return null;
136    }
137    
138    /**
139     * Get the source URI for wrapped service
140     * @param request The request
141     * @param requestedURI The requested URI
142     * @return the wrapped URI
143     */
144    protected List<String> getSourceURIs (Request request, String requestedURI)
145    {
146        List<String> sourceURIs = new ArrayList<>();
147
148        ZoneItem zoneItem = (ZoneItem) request.getAttribute(WebConstants.REQUEST_ATTR_ZONEITEM);
149        String serviceId = zoneItem.getServiceId();
150        
151        // Ex: context://WEB-INF/stylesheets/service/_wrapper/service-[cType].xsl 
152        int index = requestedURI.indexOf(".xsl");
153        
154        sourceURIs.add("context://WEB-INF/" + requestedURI.substring(0, index) + "-" + serviceId + ".xsl");
155        
156        sourceURIs.add("context://WEB-INF/" + requestedURI);
157        
158        sourceURIs.add("workspace:" + request.getAttribute("workspaceName") + "://" + requestedURI);
159        
160        return sourceURIs;
161        
162    }
163}