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.transformation.ConsistencyChecker.CHECK;
027import org.ametys.cms.transformation.ImageResolverHelper;
028import org.ametys.cms.transformation.URIResolver;
029import org.ametys.core.util.URLEncoder;
030import org.ametys.plugins.repository.UnknownAmetysObjectException;
031import org.ametys.plugins.repository.metadata.BinaryMetadata;
032import org.ametys.plugins.workspaces.project.objects.Project;
033import org.ametys.runtime.i18n.I18nizableText;
034import org.ametys.web.URIPrefixHandler;
035
036/**
037 * {@link URIResolver} for type "project-metadata".<br>
038 * These links point to a file of a project
039 */
040public class ProjectMetadataUriResolver extends AbstractLogEnabled implements URIResolver, Serviceable
041{
042    private ProjectManager _projectManager;
043    private URIPrefixHandler _webPrefixHandler;
044
045    @Override
046    public void service(ServiceManager manager) throws ServiceException
047    {
048        _projectManager = (ProjectManager) manager.lookup(ProjectManager.ROLE);
049        _webPrefixHandler = (URIPrefixHandler) manager.lookup(URIPrefixHandler.ROLE);
050    }
051
052    @Override
053    public String getType()
054    {
055        return "project-metadata";
056    }
057
058    public String resolve(String uri, boolean download, boolean absolute, boolean internal)
059    {
060        Project project = null;
061        String projectName = null;
062        String metadataName = null;
063        BinaryMetadata metadata = null;
064        
065        try
066        {
067            String[] path = uri.split(";");
068            projectName = path[0];
069            metadataName = path[1];
070            
071            project = _projectManager.getProject(projectName);
072            
073            metadata = project.getMetadataHolder().getBinaryMetadata(metadataName);
074        }
075        catch (UnknownAmetysObjectException e)
076        {
077            getLogger().warn("No metadata " + metadataName + " for project " + projectName);
078            return "";
079        }
080        catch (Exception e)
081        {
082            throw new IllegalStateException(e);
083        }
084        
085        StringBuilder resultPath = new StringBuilder();
086        resultPath.append(getUriPrefix(projectName, download, absolute, false));
087        
088        resultPath.append(project.getName())
089            .append("/_project-attachments/")
090            .append(metadataName)
091            .append("/")
092            .append(metadata.getFilename());
093        
094        String encodePath = URLEncoder.encodePath(resultPath.toString());
095        return URLEncoder.encodeURI(encodePath, 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        BinaryMetadata 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.getMetadataHolder().getBinaryMetadata(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        // TODO Auto-generated method stub
200        return null;
201    }
202
203    @Override
204    public I18nizableText getLabel(String uri)
205    {
206        // TODO Auto-generated method stub
207        return null;
208    }
209    
210    
211    /**
212     * Resolves the URI for project's illustration.<br>
213     * @param uri the uri
214     * @param sizeArguments The size arguments
215     * @param download true if the pointed resource is to be downloaded.
216     * @param absolute true if the url must be absolute
217     * @return the path to the image.
218     */
219    protected String _resolveImage(String uri, String sizeArguments, boolean download, boolean absolute)
220    {
221        Project project = null;
222        String projectName = null;
223        String metadataName = null;
224        BinaryMetadata metadata = null;
225        
226        try
227        {
228            String[] path = uri.split(";");
229            projectName = path[0];
230            metadataName = path[1];
231            
232            project = _projectManager.getProject(projectName);
233            
234            metadata = project.getMetadataHolder().getBinaryMetadata(metadataName);
235        }
236        catch (UnknownAmetysObjectException e)
237        {
238            getLogger().warn("No metadata " + metadataName + " for project " + projectName);
239            return "";
240        }
241        catch (Exception e)
242        {
243            throw new IllegalStateException(e);
244        }
245        
246        StringBuilder resultPath = new StringBuilder();
247        resultPath.append(getUriPrefix(projectName, download, absolute, false));
248        
249        String filename = metadata.getFilename();
250        int i = filename.lastIndexOf(".");
251        String extension = filename.substring(i);
252        filename = filename.substring(0, i);
253        
254        resultPath.append("/_project-images/")
255            .append(metadataName)
256            .append("/")
257            .append(filename)
258            .append(sizeArguments)
259            .append(extension);
260        
261        String encodePath = URLEncoder.encodePath(resultPath.toString());
262        return URLEncoder.encodeURI(encodePath, download ? Collections.singletonMap("download", "true") : null);
263    }
264    
265    /**
266     * Get the URI prefix
267     * @param projectName The project name
268     * @param download true if the pointed resource is to be downloaded.
269     * @param absolute true if the url must be absolute
270     * @param internal true to get an internal URI.
271     * @return the URI prefix
272     */
273    protected String getUriPrefix (String projectName, boolean download, boolean absolute, boolean internal)
274    {
275        if (internal)
276        {
277            return "cocoon://_workspaces/" + projectName;
278        }
279        else if (absolute)
280        {
281            return _webPrefixHandler.getAbsoluteUriPrefix(projectName) + "/_workspaces/" + projectName;
282        }
283        else
284        {
285            return _webPrefixHandler.getUriPrefix(projectName) + "/_workspaces/" + projectName;
286        }
287    }
288
289}