001/*
002 *  Copyright 2015 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 */
016
017package org.ametys.odf.catalog;
018
019import java.util.HashMap;
020import java.util.HashSet;
021import java.util.LinkedList;
022import java.util.List;
023import java.util.Map;
024import java.util.Set;
025
026import org.apache.avalon.framework.component.Component;
027import org.apache.avalon.framework.context.Context;
028import org.apache.avalon.framework.context.ContextException;
029import org.apache.avalon.framework.context.Contextualizable;
030import org.apache.avalon.framework.service.ServiceException;
031import org.apache.avalon.framework.service.ServiceManager;
032import org.apache.avalon.framework.service.Serviceable;
033import org.apache.cocoon.ProcessingException;
034import org.apache.commons.lang.StringUtils;
035
036import org.ametys.core.ui.Callable;
037import org.ametys.core.user.CurrentUserProvider;
038import org.ametys.core.user.User;
039import org.ametys.core.user.UserIdentity;
040import org.ametys.core.user.UserManager;
041import org.ametys.odf.ProgramItem;
042import org.ametys.odf.export.pdf.GeneratePDFEngine;
043import org.ametys.odf.program.Program;
044import org.ametys.plugins.repository.AmetysObjectIterable;
045import org.ametys.plugins.repository.AmetysObjectIterator;
046import org.ametys.plugins.repository.AmetysObjectResolver;
047import org.ametys.plugins.repository.UnknownAmetysObjectException;
048import org.ametys.runtime.i18n.I18nizableText;
049
050/**
051 * DAO for manipulating catalogs.
052 *
053 */
054public class CatalogDAO implements Serviceable, Component, Contextualizable
055{
056    /** The Avalon role */
057    public static final String ROLE = CatalogDAO.class.getName();
058    
059    /** The catalog manager */
060    protected CatalogsManager _catalogsManager;
061    
062    /** The ametys object resolver */
063    protected AmetysObjectResolver _resolver;
064    
065    /** The current user provider */
066    protected CurrentUserProvider _currentUserProvider;
067
068    /** The users manager */
069    protected UserManager _userManager;
070    
071    /** The avalon context. */
072    protected Context _context;
073    
074    /** The manager */
075    protected ServiceManager _manager;
076    
077    @Override
078    public void contextualize(Context context) throws ContextException
079    {
080        _context = context;
081    }
082    
083    @Override
084    public void service(ServiceManager manager) throws ServiceException
085    {
086        _catalogsManager = (CatalogsManager) manager.lookup(CatalogsManager.ROLE);
087        _resolver = (AmetysObjectResolver) manager.lookup(AmetysObjectResolver.ROLE);
088        _currentUserProvider = (CurrentUserProvider) manager.lookup(CurrentUserProvider.ROLE);
089        _userManager = (UserManager) manager.lookup(UserManager.ROLE);
090        _manager = manager;
091    }
092    
093    /**
094     * Creates a new ODF catalog.
095     * @param title The title of the catalog
096     * @param name The code of the catalog
097     * @param catalogNameToCopy The catalog name to copy or null
098     * @return The id and the title of the created catalog, or an error
099     * @throws ProcessingException if creation failed
100     */
101    @Callable
102    public Map<String, String> createCatalog (String title, String name, String catalogNameToCopy) throws ProcessingException
103    {
104        Map<String, String> result = new HashMap<>();
105        
106        // FIXME CMS-5758 FilterNameHelper.filterName do not authorized name with number (so name is computed from JS)
107        
108        Catalog catalog = _catalogsManager.getCatalog(name);
109        if (catalog != null)
110        {
111            result.put("message", "already-exist");
112            return result;
113        }
114        
115        Catalog newCatalog = _catalogsManager.createCatalog(name, title);
116        
117        if (StringUtils.isNotEmpty(catalogNameToCopy))
118        {
119            Catalog catalogToCopy = _catalogsManager.getCatalog(catalogNameToCopy);
120            
121            if (catalogToCopy == null)
122            {
123                result.put("message", "not-found");
124                return result;
125            }
126
127            _catalogsManager.copyCatalog(newCatalog, catalogToCopy);
128        }
129        
130        newCatalog.saveChanges();
131        
132        result.put("id", newCatalog.getId());
133        result.put("title", newCatalog.getTitle());
134        
135        return result;
136    }
137    
138    /**
139     * Edits an ODF catalog.
140     * @param id The id of the catalog to edit
141     * @param title The title of the catalog
142     * @return The id and the title of the edited catalog, or an error
143     */
144    @Callable
145    public Map<String, String> editCatalog (String id, String title)
146    {
147        Map<String, String> result = new HashMap<>();
148        
149        try
150        {
151            Catalog catalog = _resolver.resolveById(id);
152            
153            catalog.setTitle(title);
154            catalog.saveChanges();
155            
156            result.put("id", catalog.getId());
157        }
158        catch (UnknownAmetysObjectException e)
159        {
160            result.put("message", "not-found");
161        }
162        
163        return result;
164    }
165    
166    /**
167     * Set a catalog as default catalog
168     * @param id The id of catalog
169     * @return The id and the title of the edited catalog, or an error
170     */
171    @Callable
172    public synchronized Map<String, String> setDefaultCatalog(String id)
173    {
174        Map<String, String> result = new HashMap<>();
175        
176        try
177        {
178            Catalog catalog = _resolver.resolveById(id);
179            
180            Catalog defaultCatalog = _catalogsManager.getDefaultCatalog();
181            if (defaultCatalog != null)
182            {
183                defaultCatalog.setDefault(false);
184                defaultCatalog.saveChanges();
185            }
186            catalog.setDefault(true);
187            catalog.saveChanges();
188            
189            _catalogsManager.updateDefaultCatalog();
190            
191            result.put("id", catalog.getId());
192        }
193        catch (UnknownAmetysObjectException e)
194        {
195            result.put("message", "not-found");
196        }
197        
198        return result;
199    }
200    
201    /**
202     * Removes an ODF catalog.
203     * @param id The id of the catalog to remove
204     * @return The id of the deleted catalog, or an error
205     */
206    @Callable
207    public Map<String, Object> removeCatalog (String id)
208    {
209        Map<String, Object> result = new HashMap<>();
210        
211        result.put("id", id);
212        
213        Catalog catalog = _resolver.resolveById(id);
214        
215        AmetysObjectIterable<ProgramItem> programItems = _catalogsManager.getProgramItems(catalog.getName());
216        AmetysObjectIterator<ProgramItem> it = programItems.iterator();
217        
218        if (it.hasNext())
219        {
220            // Still referenced
221            result.put("error", new I18nizableText("plugin.odf", "PLUGINS_ODF_CATALOG_CATALOGACTIONS_DELETE_ERROR_STILL_REFERENCED"));
222        }
223        else
224        {
225            _catalogsManager.deleteCatalog(catalog.getId());
226        }
227        
228        return result;
229    }
230    
231    /**
232     * Gets the properties of a catalog.
233     * @param id The catalog id
234     * @return The properties of the catalog in a map
235     */
236    @Callable
237    public Map<String, Object> getCatalogProperties(String id)
238    {
239        Catalog catalog = _resolver.resolveById(id);
240        return getCatalogProperties(catalog);
241    }
242    
243    /**
244     * Gets the properties of a set of catalogs.
245     * @param ids The catalogs' id
246     * @return The properties of the catalogs
247     */
248    @Callable
249    public Map<String, Object> getCatalogsProperties(List<String> ids)
250    {
251        Map<String, Object> result = new HashMap<>();
252        
253        List<Map<String, Object>> catalogs = new LinkedList<>();
254        Set<String> unknownCatalogs = new HashSet<>();
255        
256        for (String id : ids)
257        {
258            try
259            {
260                Catalog catalog = _resolver.resolveById(id);
261                catalogs.add(getCatalogProperties(catalog));
262            }
263            catch (UnknownAmetysObjectException e)
264            {
265                unknownCatalogs.add(id);
266            }
267        }
268        
269        result.put("catalogs", catalogs);
270        result.put("unknownCatalogs", unknownCatalogs);
271        
272        return result;
273    }
274    
275    /**
276     * Generates the PDF of this catalog.
277     * @param name The name (code) of the catalog to export
278     * @param contextualParameters the contextual parameters
279     * @return An empty map, or an error
280     */
281    @Callable
282    public Map<String, Object> generatePDF(String name, Map<String, Object> contextualParameters)
283    {
284        Map<String, Object> result = new HashMap<>();
285        
286        if (GeneratePDFEngine.isRunning())
287        {
288            result.put("message", "already-running");
289        }
290        else
291        {
292            GeneratePDFEngine generatePDFEngine = new GeneratePDFEngine();
293            
294            UserIdentity identity = _currentUserProvider.getUser();
295            User currentUser = _userManager.getUser(identity.getPopulationId(), identity.getLogin());
296            
297            generatePDFEngine.setContextualParameters(contextualParameters);
298            generatePDFEngine.setCatalog(name);
299            generatePDFEngine.setIssuer(currentUser);
300            
301            try
302            {
303                // Initialize and configure the engine.
304                generatePDFEngine.initialize(_manager, _context);
305                
306                // Create the thread, mark it as daemon and start it.
307                Thread engineThread = new Thread(generatePDFEngine, "GeneratePDFEngine");
308                engineThread.setDaemon(true);
309                engineThread.start();
310            }
311            catch (Exception e)
312            {
313                throw new RuntimeException("Unable to initialize the generate pdf engine", e);
314            }
315        }
316        
317        return result;
318    }
319    
320    /**
321     * Get the properties of a catalog as a Map
322     * @param catalog The catalog
323     * @return The properties into a map object
324     */
325    public Map<String, Object> getCatalogProperties(Catalog catalog)
326    {
327        Map<String, Object> result = new HashMap<>();
328        
329        result.put("id", catalog.getId());
330        result.put("title", catalog.getTitle());
331        result.put("isDefault", catalog.isDefault());
332        result.put("code", catalog.getName());
333        
334        AmetysObjectIterable<Program> programs = _catalogsManager.getPrograms(catalog.getName());
335        result.put("nbPrograms", programs.getSize());
336        
337        return result;
338    }
339}