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.plugins.workspaces.project;
017
018import java.io.InputStream;
019import java.util.Collections;
020
021import org.apache.avalon.framework.logger.AbstractLogEnabled;
022import org.apache.avalon.framework.service.ServiceException;
023import org.apache.avalon.framework.service.ServiceManager;
024import org.apache.avalon.framework.service.Serviceable;
025
026import org.ametys.cms.data.Binary;
027import org.ametys.cms.transformation.ConsistencyChecker.CHECK;
028import org.ametys.cms.transformation.ImageResolverHelper;
029import org.ametys.cms.transformation.URIResolver;
030import org.ametys.core.util.FilenameUtils;
031import org.ametys.core.util.URIUtils;
032import org.ametys.plugins.repository.UnknownAmetysObjectException;
033import org.ametys.plugins.workspaces.project.objects.Project;
034import org.ametys.runtime.i18n.I18nizableText;
035import org.ametys.web.URIPrefixHandler;
036
037/**
038 * {@link URIResolver} for type "project-metadata".<br>
039 * These links point to a file of a project
040 */
041public class ProjectMetadataUriResolver extends AbstractLogEnabled implements URIResolver, Serviceable
042{
043    private ProjectManager _projectManager;
044    private URIPrefixHandler _webPrefixHandler;
045
046    @Override
047    public void service(ServiceManager manager) throws ServiceException
048    {
049        _projectManager = (ProjectManager) manager.lookup(ProjectManager.ROLE);
050        _webPrefixHandler = (URIPrefixHandler) manager.lookup(URIPrefixHandler.ROLE);
051    }
052
053    @Override
054    public String getType()
055    {
056        return "project-metadata";
057    }
058
059    public String resolve(String uri, boolean download, boolean absolute, boolean internal)
060    {
061        Project project = null;
062        String projectName = null;
063        String metadataName = null;
064        Binary metadata = null;
065        
066        try
067        {
068            String[] path = uri.split(";");
069            projectName = path[0];
070            metadataName = path[1];
071            
072            project = _projectManager.getProject(projectName);
073            
074            metadata = project.getValue(metadataName);
075        }
076        catch (UnknownAmetysObjectException e)
077        {
078            getLogger().warn("No metadata " + metadataName + " for project " + projectName);
079            return "";
080        }
081        catch (Exception e)
082        {
083            throw new IllegalStateException(e);
084        }
085        
086        StringBuilder resultPath = new StringBuilder();
087        resultPath.append(getUriPrefix(projectName, download, absolute, false));
088        
089        resultPath.append(project.getName())
090            .append("/_project-attachments/")
091            .append(metadataName)
092            .append("/")
093            .append(FilenameUtils.encodeName(metadata.getFilename()));
094        
095        return URIUtils.encodeURI(resultPath.toString(), download ? Collections.singletonMap("download", "true") : null);
096    }
097
098    @Override
099    public String resolveImage(String uri, int height, int width, boolean download, boolean absolute, boolean internal)
100    {
101        StringBuilder sizeSb = new StringBuilder();
102        if (width != 0 && height != 0)
103        {
104            sizeSb.append(height).append("x").append(width);
105        }
106            
107        return _resolveImage(uri, sizeSb.toString(), download, absolute);
108    }
109
110    @Override
111    public String resolveImageAsBase64(String uri, int height, int width)
112    {
113        return resolveImageAsBase64(uri, height, width, 0, 0, 0, 0);
114    }
115    
116    /**
117     * Get an image's bytes encoded as base64, optionally resized. 
118     * @param uri the image URI.
119     * @param height the specified height. Ignored if negative.
120     * @param width the specified width. Ignored if negative.
121     * @param maxHeight the maximum image height. Ignored if height or width is specified.
122     * @param maxWidth the maximum image width. Ignored if height or width is specified.
123     * @param cropHeight The cropping height. Ignored if negative.
124     * @param cropWidth The cropping width. Ignored if negative.
125     * @return the image bytes encoded as base64.
126     */
127    protected String resolveImageAsBase64(String uri, int height, int width, int maxHeight, int maxWidth, int cropHeight, int cropWidth)
128    {
129        Project project = null;
130        String projectName = null;
131        String metadataName = null;
132        Binary metadata = null;
133        
134        try
135        {
136            String[] path = uri.split(";");
137            projectName = path[0];
138            metadataName = path[1];
139            
140            project = _projectManager.getProject(projectName);
141            
142            metadata = project.getValue(metadataName);
143            
144            try (InputStream dataIs = metadata.getInputStream())
145            {
146                return ImageResolverHelper.resolveImageAsBase64(dataIs, metadata.getMimeType(), height, width, maxHeight, maxWidth, cropHeight, cropWidth);
147            }
148        }
149        catch (UnknownAmetysObjectException e)
150        {
151            getLogger().warn("No metadata " + metadataName + " for project " + projectName);
152            return "";
153        }
154        catch (Exception e)
155        {
156            throw new IllegalStateException(e);
157        }
158    }
159
160    @Override
161    public String resolveBoundedImage(String uri, int maxHeight, int maxWidth, boolean download, boolean absolute, boolean internal)
162    {
163        StringBuilder sizeSb = new StringBuilder();
164        if (maxHeight != 0 && maxWidth != 0)
165        {
166            sizeSb.append("_max").append(maxHeight).append("x").append(maxWidth);
167        }
168            
169        return _resolveImage(uri, sizeSb.toString(), download, absolute);
170    }
171
172    @Override
173    public String resolveBoundedImageAsBase64(String uri, int maxHeight, int maxWidth)
174    {
175        return resolveImageAsBase64(uri, 0, 0, maxHeight, maxWidth, 0, 0);
176    }
177
178    @Override
179    public String resolveCroppedImage(String uri, int cropHeight, int cropWidth, boolean download, boolean absolute, boolean internal)
180    {
181        StringBuilder sizeSb = new StringBuilder();
182        if (cropHeight != 0 && cropWidth != 0)
183        {
184            sizeSb.append("_crop").append(cropHeight).append("x").append(cropWidth);
185        }
186            
187        return _resolveImage(uri, sizeSb.toString(), download, absolute);
188    }
189
190    @Override
191    public String resolveCroppedImageAsBase64(String uri, int cropHeight, int cropWidth)
192    {
193        return resolveImageAsBase64(uri, 0, 0, 0, 0, cropHeight, cropWidth);
194    }
195
196    @Override
197    public CHECK checkLink(String uri, boolean shortTest)
198    {
199        return null;
200    }
201
202    @Override
203    public I18nizableText getLabel(String uri)
204    {
205        return null;
206    }
207    
208    /**
209     * Resolves the URI for project's illustration.<br>
210     * @param uri the uri
211     * @param sizeArguments The size arguments
212     * @param download true if the pointed resource is to be downloaded.
213     * @param absolute true if the url must be absolute
214     * @return the path to the image.
215     */
216    protected String _resolveImage(String uri, String sizeArguments, boolean download, boolean absolute)
217    {
218        Project project = null;
219        String projectName = null;
220        String metadataName = null;
221        Binary metadata = null;
222        
223        try
224        {
225            String[] path = uri.split(";");
226            projectName = path[0];
227            metadataName = path[1];
228            
229            project = _projectManager.getProject(projectName);
230            
231            metadata = project.getValue(metadataName);
232        }
233        catch (UnknownAmetysObjectException e)
234        {
235            getLogger().warn("No metadata " + metadataName + " for project " + projectName);
236            return "";
237        }
238        catch (Exception e)
239        {
240            throw new IllegalStateException(e);
241        }
242        
243        StringBuilder resultPath = new StringBuilder();
244        resultPath.append(getUriPrefix(projectName, download, absolute, false));
245        
246        String filename = metadata.getFilename();
247        int i = filename.lastIndexOf(".");
248        String extension = filename.substring(i);
249        filename = filename.substring(0, i);
250        
251        resultPath.append("/_project-images/")
252            .append(metadataName)
253            .append("/")
254            .append(FilenameUtils.encodeName(filename))
255            .append(sizeArguments)
256            .append(extension);
257        
258        return URIUtils.encodeURI(resultPath.toString(), download ? Collections.singletonMap("download", "true") : null);
259    }
260    
261    /**
262     * Get the URI prefix
263     * @param projectName The project name
264     * @param download true if the pointed resource is to be downloaded.
265     * @param absolute true if the url must be absolute
266     * @param internal true to get an internal URI.
267     * @return the URI prefix
268     */
269    protected String getUriPrefix (String projectName, boolean download, boolean absolute, boolean internal)
270    {
271        if (internal)
272        {
273            return "cocoon://_workspaces/" + projectName;
274        }
275        else if (absolute)
276        {
277            return _webPrefixHandler.getAbsoluteUriPrefix(projectName) + "/_workspaces/" + projectName;
278        }
279        else
280        {
281            return _webPrefixHandler.getUriPrefix(projectName) + "/_workspaces/" + projectName;
282        }
283    }
284
285}