001/*
002 *  Copyright 2014 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.flipbook;
017
018import java.net.URI;
019import java.net.URISyntaxException;
020
021import org.apache.avalon.framework.configuration.Configurable;
022import org.apache.avalon.framework.configuration.Configuration;
023import org.apache.avalon.framework.configuration.ConfigurationException;
024import org.apache.avalon.framework.logger.Logger;
025import org.apache.avalon.framework.service.ServiceException;
026import org.apache.avalon.framework.service.ServiceManager;
027import org.apache.cocoon.components.ContextHelper;
028import org.apache.cocoon.environment.Request;
029
030import org.ametys.cms.transformation.URIResolver;
031import org.ametys.core.util.URLEncoder;
032import org.ametys.plugins.explorer.resources.Resource;
033import org.ametys.plugins.repository.AmetysObject;
034import org.ametys.plugins.repository.AmetysObjectResolver;
035import org.ametys.plugins.repository.UnknownAmetysObjectException;
036import org.ametys.runtime.plugin.component.PluginAware;
037import org.ametys.web.editor.ResourceURIResolver;
038import org.ametys.web.explorer.ResourceHelper;
039import org.ametys.web.repository.SiteAwareAmetysObject;
040
041/**
042 * {@link URIResolver} for type "resource-pdf2flash".<br> TODO
043 * These links point to a document file from the resource explorer converted to flash. 
044 */
045public class Resource2FlipbookUriResolver extends ResourceURIResolver implements PluginAware, Configurable
046{
047    /** The plugin name. */
048    protected String _pluginName;
049    
050    /** The type. */
051    protected String _type;
052    
053    /** The cache resource component. */
054    protected ConvertResource2ImagesComponent _resourceComponent;
055    
056    @Override
057    public void service(ServiceManager serviceManager) throws ServiceException
058    {
059        super.service(serviceManager);
060        _resourceComponent = (ConvertResource2ImagesComponent) serviceManager.lookup(ConvertResource2ImagesComponent.ROLE);
061    }
062    
063    @Override
064    public void setPluginInfo(String pluginName, String featureName, String id)
065    {
066        _pluginName = pluginName;
067    }
068    
069    public void configure(Configuration configuration) throws ConfigurationException
070    {
071        _type = configuration.getChild("type").getValue("explorer-flipbook");
072    }
073    
074    @Override
075    public String getType()
076    {
077        return _type;
078    }
079    
080    @Override
081    protected String getResourcePath(Resource resource)
082    {
083        String fullPath = resource.getPath();
084        
085        if (fullPath.startsWith(ResourceHelper.SHARED_RESOURCE_PATH))
086        {
087            return fullPath.substring(ResourceHelper.SHARED_RESOURCE_PATH.length());
088        }
089        else
090        {
091            return super.getResourcePath(resource);
092        }
093    }
094    
095    @Override
096    public String resolve(String uri, boolean download, boolean absolute, boolean internal)
097    {
098        Request request = ContextHelper.getRequest(_context);
099        
100        String path;
101        Resource resource = null;
102        String siteName = null;
103        try
104        {
105            resource = (Resource) _resolver.resolveById(uri);
106            path = getResourcePath(resource);
107            
108            if (resource.getPath().startsWith(ResourceHelper.SHARED_RESOURCE_PATH))
109            {
110                siteName = (String) request.getAttribute("siteName");
111                
112                if (siteName == null)
113                {
114                    siteName = (String) request.getAttribute("site");
115                }
116            }
117            else
118            {
119                siteName = _getSiteName(resource);
120            }
121        }
122        catch (UnknownAmetysObjectException e)
123        {
124            getLogger().warn("Link to unexisting resource " + uri);
125            return "";
126        }
127        
128        if (!_resourceComponent.isMimeTypeSupported(resource.getMimeType()))
129        {
130            return super.resolve(uri, download, absolute, internal);
131        }
132
133        StringBuilder result = new StringBuilder();
134        
135        // plugins/flipbook/<site>_resource-flipbook/<path>/<to>/<resource>/<fileName>/book.html
136        result.append(getUriPrefix(resource, download, internal, absolute));
137        result.append("/_")
138              .append(getRealPrefix(resource, "resource-flipbook"))
139              .append(path)
140              .append("/book.html");
141        
142        new CacheThread(resource.getId(), siteName, _resolver, getLogger()).start();
143        
144        // Encode twice
145        return URLEncoder.encodePath(URLEncoder.encodePath(result.toString()));
146    }
147    
148    @Override
149    public String resolveImage(String uri, int height, int width, boolean download, boolean absolute, boolean internal)
150    {
151        Resource resource = null;
152        try
153        {
154            resource = (Resource) _resolver.resolveById(uri);
155        }
156        catch (UnknownAmetysObjectException e)
157        {
158            getLogger().warn("Link to unexisting resource " + uri);
159            return "";
160        }
161        
162        try
163        {
164            if (!_resourceComponent.isMimeTypeSupported(resource.getMimeType()))
165            { 
166                String defaultPath = getUriPrefix(resource, download, absolute, internal)
167                        + "/pages" 
168                        + "/error"
169                        + "/thumbnail_"
170                        + height + "x" + width
171                        + ".png";
172                
173                return new URI(null, null, defaultPath, null, null).toASCIIString();
174            }
175
176            new CacheThread(resource.getId(), _getSiteName(resource), _resolver, getLogger()).start();
177            
178            String result = getUriPrefix(resource, download, absolute, internal)
179                    + "/" + getRealPrefix(resource, "resources")
180                    + "/" + resource.getResourcePath()
181                    + "/pages" 
182                    + "/thumbnail_"
183                    + height + "x" + width
184                    + ".png";
185            
186            return new URI(null, null, result, null, null).toASCIIString();
187        }
188        catch (URISyntaxException e)
189        {
190            throw new RuntimeException(e);
191        }
192    }
193    
194    @Override
195    public String resolveBoundedImage(String uri, int maxHeight, int maxWidth, boolean download, boolean absolute, boolean internal)
196    {
197        if (maxHeight == 0 && maxWidth == 0)
198        {
199            return resolve(uri, download, absolute, internal);
200        }
201        
202        Resource resource = null;
203        try
204        {
205            resource = (Resource) _resolver.resolveById(uri);
206        }
207        catch (UnknownAmetysObjectException e)
208        {
209            getLogger().warn("Link to unexisting resource " + uri);
210            return "";
211        }
212        
213        try
214        {
215            if (!_resourceComponent.isMimeTypeSupported(resource.getMimeType()))
216            { 
217                String defaultPath = getUriPrefix(resource, download, absolute, internal)
218                        + "/pages" 
219                        + "/error"
220                        + "/thumbnail_max"
221                        + maxHeight + "x" + maxWidth
222                        + ".png";
223                
224                return new URI(null, null, defaultPath, null, null).toASCIIString();
225            }
226            
227            new CacheThread(resource.getId(), _getSiteName(resource), _resolver, getLogger()).start();
228
229            String result = getUriPrefix(resource, download, absolute, internal)
230                    + "/" + getRealPrefix(resource, "resources")
231                    + "/" + resource.getResourcePath()
232                    + "/pages" 
233                    + "/thumbnail_max"
234                    + maxHeight + "x" + maxWidth
235                    + ".png";
236            
237            return new URI(null, null, result, null, null).toASCIIString();
238        }
239        catch (URISyntaxException e)
240        {
241            throw new RuntimeException(e);
242        }
243    }
244    
245    @Override
246    protected String getUriPrefix(AmetysObject object, boolean download, boolean absolute, boolean internal)
247    {
248        Request request = ContextHelper.getRequest(_context);
249        
250        String siteName = null;
251        if (object instanceof SiteAwareAmetysObject)
252        {
253            siteName = ((SiteAwareAmetysObject) object).getSiteName();
254        }
255        else
256        {
257            siteName = (String) request.getAttribute("siteName");
258            
259            if (siteName == null)
260            {
261                siteName = (String) request.getAttribute("site");
262            }
263        }
264        
265        String initialSiteName = (String) ContextHelper.getRequest(_context).getAttribute("initialSiteName");
266        boolean isInitialSite = initialSiteName == null || initialSiteName.equals(siteName);
267        
268        String uriPrefix;
269        if (internal)
270        {
271            uriPrefix = "cocoon://" + siteName;
272        }
273        else if (absolute || !isInitialSite)
274        {
275            uriPrefix = _webPrefixHandler.getAbsoluteUriPrefix(siteName);
276        }
277        else
278        {
279            uriPrefix = _webPrefixHandler.getUriPrefix(siteName);
280        }
281        
282        uriPrefix +=  "/_plugins/" + _pluginName + "/" + siteName;
283        return uriPrefix;
284    }
285
286    private class CacheThread extends Thread 
287    {
288        private String _resourceId;
289        private String _siteName;
290        private Logger _cacheLogger;
291        private AmetysObjectResolver _cacheResolver;
292        
293        public CacheThread(String resourceId, String siteName, AmetysObjectResolver cacheResolver, Logger cacheLogger) 
294        {
295            _resourceId = resourceId;
296            _siteName = siteName;
297            _cacheLogger = cacheLogger;
298            _cacheResolver = cacheResolver;
299            setDaemon(true);
300            setName("FlipbookCacheResourceCreator");
301        }
302        
303        @Override
304        public void run() 
305        {
306            try
307            {
308                Resource resource = _cacheResolver.resolveById(_resourceId);
309                _resourceComponent.doCache(resource, _siteName);
310            }
311            catch (Exception e)
312            {
313                _cacheLogger.error("An error occurred during creating cache for resource : " + _resourceId);
314            }
315        }
316    }
317}