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.cms.transformation;
017
018import java.io.InputStream;
019import java.util.Collections;
020
021import org.apache.avalon.framework.context.Context;
022import org.apache.avalon.framework.context.ContextException;
023import org.apache.avalon.framework.context.Contextualizable;
024import org.apache.avalon.framework.logger.AbstractLogEnabled;
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.components.ContextHelper;
029import org.apache.cocoon.environment.Request;
030
031import org.ametys.cms.URIPrefixHandler;
032import org.ametys.cms.repository.Content;
033import org.ametys.cms.transformation.ConsistencyChecker.CHECK;
034import org.ametys.core.util.URLEncoder;
035import org.ametys.plugins.explorer.resources.Resource;
036import org.ametys.plugins.repository.AmetysObject;
037import org.ametys.plugins.repository.AmetysObjectResolver;
038import org.ametys.plugins.repository.UnknownAmetysObjectException;
039import org.ametys.runtime.i18n.I18nizableText;
040
041/**
042 * {@link URIResolver} for type "attachment".<br>
043 * These links point to a file from the attachments of the current Content.
044 */
045public class AttachmentURIResolver extends AbstractLogEnabled implements URIResolver, Serviceable, Contextualizable
046{
047    /** The ametys resolver */
048    protected AmetysObjectResolver _resolver;
049    /** The avalon context */
050    protected Context _context;
051    /** The URI prefix handler */
052    protected URIPrefixHandler _prefixHandler;
053    
054    @Override
055    public void contextualize(Context context) throws ContextException
056    {
057        _context = context;
058    }
059
060    @Override
061    public void service(ServiceManager manager) throws ServiceException
062    {
063        _resolver = (AmetysObjectResolver) manager.lookup(AmetysObjectResolver.ROLE);
064        _prefixHandler = (URIPrefixHandler) manager.lookup(URIPrefixHandler.ROLE);
065    }
066    
067    @Override
068    public String getType()
069    {
070        return "attachment-content";
071    }
072    
073    @Override
074    public String resolve(String uri, boolean download, boolean absolute, boolean internal)
075    {
076        Request request = ContextHelper.getRequest(_context);
077        String path;
078        Content content = null;
079        String contentName = null;
080        
081        try
082        {
083            Resource resource = (Resource) _resolver.resolveById(uri);
084            path = resource.getResourcePath();
085            
086            content = (Content) request.getAttribute(Content.class.getName());
087            contentName = content.getName();
088        }
089        catch (UnknownAmetysObjectException e)
090        {
091            getLogger().warn("Link to unexisting resource " + uri);
092            return "";
093        }
094        catch (Exception e)
095        {
096            throw new IllegalStateException(e);
097        }
098        
099        StringBuilder resultPath = new StringBuilder();
100        resultPath.append(getUriPrefix(content, download, internal, absolute));
101        
102        resultPath.append("/_attachments/")
103            .append(contentName)
104            .append(path);
105        
106        String encodePath = URLEncoder.encodePath(resultPath.toString());
107        return URLEncoder.encodeURI(encodePath, download ? Collections.singletonMap("download", "true") : null);
108    }
109    
110    /**
111     * Get the URI prefix
112     * @param object The object
113     * @param download true if the pointed resource is to be downloaded.
114     * @param absolute true if the url must be absolute
115     * @param internal true to get an internal URI.
116     * @return the URI prefix
117     */
118    protected String getUriPrefix (AmetysObject object, boolean download, boolean internal, boolean absolute)
119    {
120        if (internal)
121        {
122            return "cocoon://";
123        }
124        else if (absolute)
125        {
126            return _prefixHandler.getAbsoluteUriPrefix();
127        }
128        else
129        {
130            return _prefixHandler.getUriPrefix();
131        }
132    }
133    
134    @Override
135    public String resolveImage(String uri, int height, int width, boolean download, boolean absolute, boolean internal)
136    {
137        if (height == 0 && width == 0)
138        {
139            return resolve(uri, download, absolute, internal);
140        }
141        
142        Request request = ContextHelper.getRequest(_context);
143        String path;
144        Content content = null;
145        String contentName = null;
146        try
147        {
148            Resource resource = (Resource) _resolver.resolveById(uri);
149            path = resource.getResourcePath();
150            
151            content = (Content) request.getAttribute(Content.class.getName());
152            contentName = content.getName();
153        }
154        catch (UnknownAmetysObjectException e)
155        {
156            getLogger().warn("Link to unexisting resource " + uri);
157            return "";
158        }
159        catch (Exception e)
160        {
161            throw new IllegalStateException(e);
162        }
163        
164        int i = path.lastIndexOf(".");
165        String extension = path.substring(i);
166        path = path.substring(0, i);
167        
168        StringBuilder result = new StringBuilder();
169        result.append(getUriPrefix(content, download, internal, absolute));
170        
171        result.append("/_attachments-images/")
172              .append(contentName)
173              .append(path)
174              .append("_").append(height).append("x").append(width)
175              .append(extension);
176        
177        String encodePath = URLEncoder.encodePath(result.toString());
178        return URLEncoder.encodeURI(encodePath, download ? Collections.singletonMap("download", "true") : null);
179    }
180    
181    @Override
182    public String resolveImageAsBase64(String uri, int height, int width)
183    {
184        return resolveImageAsBase64(uri, height, width, 0, 0);
185    }
186    
187    @Override
188    public String resolveBoundedImage(String uri, int maxHeight, int maxWidth, boolean download, boolean absolute, boolean internal)
189    {
190        if (maxHeight == 0 && maxWidth == 0)
191        {
192            return resolve(uri, download, absolute, internal);
193        }
194        
195        Request request = ContextHelper.getRequest(_context);
196        String path;
197        Content content = null;
198        String contentName = null;
199        try
200        {
201            Resource resource = (Resource) _resolver.resolveById(uri);
202            path = resource.getResourcePath();
203            
204            content = (Content) request.getAttribute(Content.class.getName());
205            contentName = content.getName();
206           
207        }
208        catch (UnknownAmetysObjectException e)
209        {
210            getLogger().warn("Link to unexisting resource " + uri);
211            return "";
212        }
213        catch (Exception e)
214        {
215            throw new IllegalStateException(e);
216        }
217        
218        int i = path.lastIndexOf(".");
219        String extension = path.substring(i);
220        path = path.substring(0, i);
221        
222        StringBuilder result = new StringBuilder();
223        result.append(getUriPrefix(content, download, internal, absolute));
224        
225        result.append("/_attachments-images/")
226              .append(contentName)
227              .append(path)
228              .append("_max").append(maxHeight).append("x").append(maxWidth)
229              .append(extension);
230        
231        String encodePath = URLEncoder.encodePath(result.toString());
232        return URLEncoder.encodeURI(encodePath, download ? Collections.singletonMap("download", "true") : null);
233    }
234    
235    @Override
236    public String resolveBoundedImageAsBase64(String uri, int maxHeight, int maxWidth)
237    {
238        return resolveImageAsBase64(uri, 0, 0, maxHeight, maxWidth);
239    }
240    
241    /**
242     * Get an image's bytes encoded as base64, optionally resized. 
243     * @param uri the image URI.
244     * @param height the specified height. Ignored if negative.
245     * @param width the specified width. Ignored if negative.
246     * @param maxHeight the maximum image height. Ignored if height or width is specified.
247     * @param maxWidth the maximum image width. Ignored if height or width is specified.
248     * @return the image bytes encoded as base64.
249     */
250    protected String resolveImageAsBase64(String uri, int height, int width, int maxHeight, int maxWidth)
251    {
252        try
253        {
254            Resource resource = (Resource) _resolver.resolveById(uri);
255            
256            try (InputStream dataIs = resource.getInputStream())
257            {
258                return ImageResolverHelper.resolveImageAsBase64(dataIs, resource.getMimeType(), height, width, maxHeight, maxWidth);
259            }
260        }
261        catch (UnknownAmetysObjectException e)
262        {
263            getLogger().warn("Link to unexisting resource " + uri);
264            return "";
265        }
266        catch (Exception e)
267        {
268            throw new IllegalStateException(e);
269        }
270    }
271    
272    @Override
273    public CHECK checkLink(String uri, boolean shortTest)
274    {
275        try
276        {
277            _resolver.resolveById(uri);
278            return CHECK.SUCCESS;
279        }
280        catch (UnknownAmetysObjectException e)
281        {
282            return CHECK.NOT_FOUND;
283        }
284    }
285    
286    @Override
287    public I18nizableText getLabel(String uri)
288    {
289        try
290        {
291            Resource resource = (Resource) _resolver.resolveById(uri);
292            return new I18nizableText("plugin.cms", "PLUGINS_CMS_LINK_ATTACHMENT_LABEL", Collections.singletonList(resource.getResourcePath()));
293        }
294        catch (UnknownAmetysObjectException e)
295        {
296            return new I18nizableText("plugin.cms", "PLUGINS_CMS_LINK_ATTACHMENT_UNKNOWN");
297        }
298    }
299}