001/*
002 *  Copyright 2017 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.cms.remote;
017
018import java.util.Collections;
019import java.util.HashMap;
020import java.util.Map;
021import java.util.regex.Matcher;
022import java.util.regex.Pattern;
023
024import org.apache.avalon.framework.context.Context;
025import org.apache.avalon.framework.context.ContextException;
026import org.apache.avalon.framework.context.Contextualizable;
027import org.apache.avalon.framework.service.ServiceException;
028import org.apache.avalon.framework.service.ServiceManager;
029import org.apache.avalon.framework.service.Serviceable;
030import org.apache.cocoon.components.ContextHelper;
031import org.apache.cocoon.environment.Request;
032import org.apache.commons.lang.StringUtils;
033
034import org.ametys.cms.transformation.ConsistencyChecker.CHECK;
035import org.ametys.cms.transformation.URIResolver;
036import org.ametys.cms.transformation.URIResolverExtensionPoint;
037import org.ametys.cms.transformation.xslt.ResolveURIComponent;
038import org.ametys.runtime.config.Config;
039import org.ametys.runtime.i18n.I18nizableTextParameter;
040import org.ametys.runtime.i18n.I18nizableText;
041import org.ametys.runtime.workspace.WorkspaceMatcher;
042
043
044/**
045 * {@link URIResolver} for type "remote".<br>
046 * This resolver is a proxy to another type to be called from remote url.
047 * The resolved uri are necessary absolutes.
048 */
049public class RemoteURIResolver implements URIResolver, Serviceable, Contextualizable
050{
051    private static final Pattern __URI_PATTERN = Pattern.compile("([^;]*);(.*)");
052    
053    /** The context */
054    protected Context _context;
055    
056    /** The ametys uri resolver */
057    protected URIResolverExtensionPoint _uriResolverEP;
058    
059    @Override
060    public void service(ServiceManager manager) throws ServiceException
061    {
062        _uriResolverEP = (URIResolverExtensionPoint) manager.lookup(URIResolverExtensionPoint.ROLE);
063    }
064    
065    @Override
066    public void contextualize(Context context) throws ContextException
067    {
068        _context = context;
069    }
070    
071    @Override
072    public String getType()
073    {
074        return "remote";
075    }
076
077    @Override
078    public String resolve(String uri, boolean download, boolean absolute, boolean internal)
079    {
080        Request request = ContextHelper.getRequest(_context);
081        
082        ProxiedUri proxiedUri = getProxiedUri(uri);
083        
084        return getAbsoluteRemoteUri(request, ResolveURIComponent.resolve(proxiedUri.getType(), proxiedUri.getUri(), download, false, false));
085    }
086
087    @Override
088    public String resolveImage(String uri, int height, int width, boolean download, boolean absolute, boolean internal)
089    {
090        Request request = ContextHelper.getRequest(_context);
091        
092        ProxiedUri proxiedUri = getProxiedUri(uri);
093        
094        return getAbsoluteRemoteUri(request, ResolveURIComponent.resolveImage(proxiedUri.getType(), proxiedUri.getUri(), height, width, download, false, false));
095    }
096
097    @Override
098    public String resolveImageAsBase64(String uri, int height, int width)
099    {
100        Request request = ContextHelper.getRequest(_context);
101        
102        ProxiedUri proxiedUri = getProxiedUri(uri);
103        
104        return getAbsoluteRemoteUri(request, ResolveURIComponent.resolveImage(proxiedUri.getType(), proxiedUri.getUri(), height, width));
105    }
106
107    @Override
108    public String resolveBoundedImage(String uri, int maxHeight, int maxWidth, boolean download, boolean absolute, boolean internal)
109    {
110        Request request = ContextHelper.getRequest(_context);
111        
112        ProxiedUri proxiedUri = getProxiedUri(uri);
113        
114        return getAbsoluteRemoteUri(request, ResolveURIComponent.resolveBoundedImage(proxiedUri.getType(), proxiedUri.getUri(), maxHeight, maxWidth, download, false, false));
115    }
116
117    @Override
118    public String resolveBoundedImageAsBase64(String uri, int maxHeight, int maxWidth)
119    {
120        Request request = ContextHelper.getRequest(_context);
121        
122        ProxiedUri proxiedUri = getProxiedUri(uri);
123        
124        return getAbsoluteRemoteUri(request, ResolveURIComponent.resolveBoundedImage(proxiedUri.getType(), proxiedUri.getUri(), maxHeight, maxWidth));
125    }
126
127    @Override
128    public String resolveCroppedImage(String uri, int cropHeight, int cropWidth, boolean download, boolean absolute, boolean internal)
129    {
130        Request request = ContextHelper.getRequest(_context);
131        
132        ProxiedUri proxiedUri = getProxiedUri(uri);
133        
134        return getAbsoluteRemoteUri(request, ResolveURIComponent.resolveCroppedImage(proxiedUri.getType(), proxiedUri.getUri(), cropHeight, cropWidth, download, false, false));
135    }
136
137    @Override
138    public String resolveCroppedImageAsBase64(String uri, int cropHeight, int cropWidth)
139    {
140        Request request = ContextHelper.getRequest(_context);
141        
142        ProxiedUri proxiedUri = getProxiedUri(uri);
143        
144        return getAbsoluteRemoteUri(request, ResolveURIComponent.resolveCroppedImage(proxiedUri.getType(), proxiedUri.getUri(), cropHeight, cropWidth));
145    }
146
147    @Override
148    public CHECK checkLink(String uri, boolean shortTest)
149    {
150        ProxiedUri proxiedUri = getProxiedUri(uri);
151
152        URIResolver resolver = _uriResolverEP.getResolverForType(proxiedUri.getType());
153        if (resolver != null)
154        {
155            return resolver.checkLink(proxiedUri.getUri(), shortTest);
156        }
157        
158        return CHECK.NOT_FOUND;
159    }
160
161    @Override
162    public I18nizableText getLabel(String uri)
163    {
164        ProxiedUri proxiedUri = getProxiedUri(uri);
165        URIResolver resolver = _uriResolverEP.getResolverForType(proxiedUri.getType());
166        if (resolver != null)
167        {
168            I18nizableText label = resolver.getLabel(proxiedUri.getUri());
169            Map<String, I18nizableTextParameter> params = new HashMap<>();
170            params.put("uri", label);
171            return new I18nizableText("plugin.cms", "PLUGINS_CMS_LINK_REMOTE_LABEL", params);
172        }
173        
174        return new I18nizableText("plugin.cms", "PLUGINS_CMS_LINK_REMOTE_UNKNOWN_TYPE", Collections.singletonList(proxiedUri.getType()));
175    }
176    
177    /**
178     * Get the absolute proxied uri
179     * @param request the request
180     * @param resolvedUri the resolved uri
181     * @return the absolute proxied url
182     */
183    protected String getAbsoluteRemoteUri(Request request, String resolvedUri)
184    {
185        String uriPrefix = getUriPrefix(request);
186        return getAbsoluteRemoteUriPrefix() + (resolvedUri.startsWith(uriPrefix) ? StringUtils.substringAfter(resolvedUri, uriPrefix) : resolvedUri);
187    }
188    
189    
190    /**
191     * Get the absolute URI prefix
192     * @return the URI prefix
193     */
194    protected String getAbsoluteRemoteUriPrefix()
195    {
196        StringBuilder result = new StringBuilder();
197        
198        String cmsUrl = Config.getInstance().getValue("cms.url");
199        
200        result.append(cmsUrl)
201            .append(cmsUrl.endsWith("/") ? "" : "/")
202            .append("_cms/remote");
203            
204        return result.toString();
205    }
206    
207    /**
208     * Get the URI prefix (non absolute) for resolved uri
209     * @param request The request
210     * @return the URI prefix
211     */
212    protected String getUriPrefix(Request request)
213    {
214        String workspaceURI = (String) request.getAttribute(WorkspaceMatcher.WORKSPACE_URI);
215        return request.getContextPath() + workspaceURI;
216    }
217    
218    /**
219     * Get the proxied uri
220     * @param uri The requested uri
221     * @return the proxied uri or null
222     * @throws IllegalArgumentException The uri does match the expected pattern
223     */
224    protected ProxiedUri getProxiedUri(String uri) throws IllegalArgumentException
225    {
226        Matcher matcher = __URI_PATTERN.matcher(uri);
227        if (matcher.matches())
228        {
229            String type = matcher.group(1);
230            String initialUri = matcher.group(2);
231
232            return new ProxiedUri(type, initialUri);
233        }
234        
235        throw new IllegalArgumentException("The uri " + uri + " does not match the regular expression " + __URI_PATTERN.pattern());
236    }
237    
238    /**
239     * Proxied URI
240     *
241     */
242    protected class ProxiedUri
243    {
244        private String _uri;
245        private String _type;
246        
247        /**
248         * Constructor
249         * @param type The type
250         * @param uri The uri to proxy
251         */
252        public ProxiedUri(String type, String uri)
253        {
254            _type = type;
255            _uri = uri;
256        }
257        
258        /**
259         * Get the uri
260         * @return the uri
261         */
262        public String getUri()
263        {
264            return _uri;
265        }
266        
267        
268        /**
269         * Get the object.
270         * @return the object
271         */
272        public String getType()
273        {
274            return _type;
275        }
276    }
277
278}