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 */
016package org.ametys.web.editor;
017
018import java.util.HashMap;
019import java.util.Map;
020
021import org.apache.avalon.framework.service.ServiceException;
022import org.apache.avalon.framework.service.ServiceManager;
023import org.apache.cocoon.components.ContextHelper;
024import org.apache.cocoon.environment.Request;
025
026import org.ametys.cms.repository.Content;
027import org.ametys.cms.transformation.URIResolver;
028import org.ametys.core.util.URLEncoder;
029import org.ametys.plugins.repository.UnknownAmetysObjectException;
030import org.ametys.plugins.repository.metadata.RichText;
031import org.ametys.plugins.repository.metadata.UnknownMetadataException;
032import org.ametys.plugins.repository.version.VersionableAmetysObject;
033import org.ametys.web.URIPrefixHandler;
034import org.ametys.web.repository.content.WebContent;
035
036/**
037 * {@link URIResolver} for type "local".resources local to a Content
038 * These links or images point resources local to a Content.
039 */
040public class LocalURIResolver extends org.ametys.cms.transformation.LocalURIResolver
041{
042    /** The URI prefix handler */
043    protected URIPrefixHandler _prefixHandler;
044
045    @Override
046    public void service(ServiceManager manager) throws ServiceException
047    {
048        super.service(manager);
049        _prefixHandler = (URIPrefixHandler) manager.lookup(URIPrefixHandler.ROLE);
050    }
051    
052    @Override
053    public String getType()
054    {
055        return "local";
056    }
057
058    @Override
059    public String resolve(String uri, boolean download, boolean absolute, boolean internal)
060    {
061        // uri are like content://UUID@metadata;data/file.ext
062        int i = uri.indexOf('@');
063        int j = uri.indexOf(';', i);
064        String id = uri.substring(0, i);
065        String metadata = uri.substring(i + 1, j);
066        String path = uri.substring(j + 1);
067
068        try
069        {
070            Request request = ContextHelper.getRequest(_context);
071            
072            String contentVersion = null;
073            // The content should be the one from request (UUID) but in that case, getRevision will be always the head on
074            Content content = (Content) request.getAttribute(Content.class.getName()); 
075            if (content == null)
076            {
077                // Some time (such as frontoffice edition) the image is rendered with no content in attrbiute
078                content = _ametysObjectResolver.resolveById(id);
079            }
080
081            String siteName;
082            if (content instanceof WebContent)
083            {
084                siteName = ((WebContent) content).getSiteName();
085            }
086            else
087            {
088                siteName = (String) request.getAttribute("siteName");
089            }
090            
091            if (siteName == null)
092            {
093                return super.resolve(uri, download, absolute, internal);
094            }
095            
096            if (id.equals(content.getId()))
097            {
098                contentVersion = ((VersionableAmetysObject) content).getRevision();
099            }
100            
101            RichText richText = _getMeta(content.getMetadataHolder(), metadata);
102            try
103            {
104                richText.getAdditionalDataFolder().getFile(path);
105            }
106            catch (UnknownAmetysObjectException e)
107            {
108                getLogger().warn("Cannot resolve link " + uri);
109                return "";
110            }
111            
112            Map<String, String> params = new HashMap<>();
113            
114            if (download)
115            {
116                params.put("download", "true");
117            }
118            
119            if (contentVersion != null)
120            {
121                params.put("contentVersion", contentVersion);
122            }
123            
124            StringBuilder resultPath = new StringBuilder();
125            
126            if (internal)
127            {
128                resultPath.append("cocoon://").append(siteName);
129            }
130            else if (absolute)
131            {
132                resultPath.append(_prefixHandler.getAbsoluteUriPrefix(siteName));
133            }
134            else
135            {
136                resultPath.append(_prefixHandler.getUriPrefix(siteName));
137            }
138            
139            resultPath.append("/_contents")
140                .append(content.getPath().replaceAll(":", "%3A"))
141                .append("/_metadata/").append(metadata)
142                .append("/_data/")
143                .append(URLEncoder.encodePath(path));
144            
145            return URLEncoder.encodeURI(resultPath.toString(), params);
146        }
147        catch (Exception e)
148        {
149            throw new IllegalStateException(e);
150        }
151    }
152    
153    @Override
154    public String resolveImage(String uri, int height, int width, boolean download, boolean absolute, boolean internal)
155    {
156        if (height == 0 && width == 0)
157        {
158            return resolve(uri, download, absolute, internal);
159        }
160        
161        // uri are like content://UUID@metadata;data/file.ext
162        int i = uri.indexOf('@');
163        int j = uri.indexOf(';', i);
164        String id = uri.substring(0, i);
165        String metadata = uri.substring(i + 1, j);
166        String path = uri.substring(j + 1);
167
168        try
169        {
170            Request request = ContextHelper.getRequest(_context);
171            
172            String contentVersion = null;
173            Content content = (Content) request.getAttribute(Content.class.getName()); // FIXME the content should be the one from request (UUID) but in that case, getRevision will be always the head one
174            if (content == null)
175            {
176                throw new IllegalStateException("Cannot resolve a local link to an unknown content for uri " + request.getRequestURI());
177            }
178            if (id.equals(content.getId())) // FIXME should be the right one directly : we should not take the one from the request
179            {
180                contentVersion = ((VersionableAmetysObject) content).getRevision();
181            }
182
183            String siteName;
184            if (content instanceof WebContent)
185            {
186                siteName = ((WebContent) content).getSiteName();
187            }
188            else
189            {
190                siteName = (String) request.getAttribute("siteName");
191            }
192            
193            RichText richText = _getMeta(content.getMetadataHolder(), metadata);
194            try
195            {
196                richText.getAdditionalDataFolder().getFile(path);
197            }
198            catch (UnknownAmetysObjectException e)
199            {
200                getLogger().warn("Cannot resolve link " + uri);
201                return "";
202            }
203            catch (UnknownMetadataException e)
204            {
205                getLogger().warn("Cannot resolve link " + uri);
206                return "";
207            }
208            
209            StringBuilder resultPath = new StringBuilder();
210            
211            if (internal)
212            {
213                resultPath.append("cocoon://").append(siteName);
214            }
215            else if (absolute)
216            {
217                resultPath.append(_prefixHandler.getAbsoluteUriPrefix(siteName));
218            }
219            else
220            {
221                resultPath.append(_prefixHandler.getUriPrefix(siteName));
222            }
223            
224            resultPath.append("/_contents-images")
225                    .append(content.getPath().replaceAll(":", "%3A"))
226                    .append("/_metadata/").append(metadata)
227                    .append("/_data/")
228                    .append(URLEncoder.encodePath(path))
229                    .append("_").append(height).append("x").append(width);
230          
231            Map<String, String> params = new HashMap<>();
232            if (download)
233            {
234                params.put("download", "true");
235            }
236            if (contentVersion != null)
237            {
238                params.put("contentVersion", contentVersion);
239            }
240            
241            return URLEncoder.encodeURI(resultPath.toString(), params);
242        }
243        catch (Exception e)
244        {
245            throw new IllegalStateException(e);
246        }
247    }
248    
249    @Override
250    public String resolveBoundedImage(String uri, int maxHeight, int maxWidth, boolean download, boolean absolute, boolean internal)
251    {
252        if (maxHeight == 0 && maxWidth == 0)
253        {
254            return resolve(uri, download, absolute, internal);
255        }
256        
257        // uri are like content://UUID@metadata;data/file.ext
258        int i = uri.indexOf('@');
259        int j = uri.indexOf(';', i);
260        String id = uri.substring(0, i);
261        String metadata = uri.substring(i + 1, j);
262        String path = uri.substring(j + 1);
263
264        try
265        {
266            Request request = ContextHelper.getRequest(_context);
267            
268            String contentVersion = null;
269            Content content = (Content) request.getAttribute(Content.class.getName()); // FIXME the content should be the one from request (UUID) but in that cas, getRevision will be always the head on
270            if (content == null)
271            {
272                throw new IllegalStateException("Cannot resolve a local link to an unknown content for uri " + request.getRequestURI());
273            }
274            if (id.equals(content.getId())) // FIXME should be the right one directly : we should not take the one from the request
275            {
276                contentVersion = ((VersionableAmetysObject) content).getRevision();
277            }
278            
279            String siteName;
280            if (content instanceof WebContent)
281            {
282                siteName = ((WebContent) content).getSiteName();
283            }
284            else
285            {
286                siteName = (String) request.getAttribute("siteName");
287            }
288            
289            RichText richText = _getMeta(content.getMetadataHolder(), metadata);
290            try
291            {
292                richText.getAdditionalDataFolder().getFile(path);
293            }
294            catch (UnknownAmetysObjectException e)
295            {
296                getLogger().warn("Cannot resolve link " + uri);
297                return "";
298            }
299            
300            StringBuilder resultPath = new StringBuilder();
301            
302            if (internal)
303            {
304                resultPath.append("cocoon://").append(siteName);
305            }
306            else if (absolute)
307            {
308                resultPath.append(_prefixHandler.getAbsoluteUriPrefix(siteName));
309            }
310            else
311            {
312                resultPath.append(_prefixHandler.getUriPrefix(siteName));
313            }
314            
315            resultPath.append("/_contents-images")
316                .append(content.getPath().replaceAll(":", "%3A"))
317                .append("/_metadata/").append(metadata)
318                .append("/_data/")
319                .append(URLEncoder.encodePath(path))
320                .append("_max").append(maxWidth).append("x").append(maxWidth);
321  
322            Map<String, String> params = new HashMap<>();
323            if (download)
324            {
325                params.put("download", "true");
326            }
327            if (contentVersion != null)
328            {
329                params.put("contentVersion", contentVersion);
330            }
331            
332            return URLEncoder.encodeURI(resultPath.toString(), params);
333        }
334        catch (Exception e)
335        {
336            throw new IllegalStateException(e);
337        }
338    }
339}