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