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 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            result.put("id", catalog.getId());
190        }
191        catch (UnknownAmetysObjectException e)
192        {
193            result.put("message", "not-found");
194        }
195        
196        return result;
197    }
198    
199    /**
200     * Removes an ODF catalog.
201     * @param id The id of the catalog to remove
202     * @return The id of the deleted catalog, or an error
203     */
204    @Callable
205    public Map<String, Object> removeCatalog (String id)
206    {
207        Map<String, Object> result = new HashMap<>();
208        
209        result.put("id", id);
210        
211        Catalog catalog = _resolver.resolveById(id);
212        
213        AmetysObjectIterable<ProgramItem> programItems = _catalogsManager.getProgramItems(catalog.getName());
214        AmetysObjectIterator<ProgramItem> it = programItems.iterator();
215        
216        if (it.hasNext())
217        {
218            // Still referenced
219            result.put("error", new I18nizableText("plugin.odf", "PLUGINS_ODF_CATALOG_CATALOGACTIONS_DELETE_ERROR_STILL_REFERENCED"));
220        }
221        else
222        {
223            _catalogsManager.deleteCatalog(catalog.getId());
224        }
225        
226        return result;
227    }
228    
229    /**
230     * Gets the properties of a catalog.
231     * @param id The catalog id
232     * @return The properties of the catalog in a map
233     */
234    @Callable
235    public Map<String, Object> getCatalogProperties(String id)
236    {
237        Catalog catalog = _resolver.resolveById(id);
238        return getCatalogProperties(catalog);
239    }
240    
241    /**
242     * Gets the properties of a set of catalogs.
243     * @param ids The catalogs' id
244     * @return The properties of the catalogs
245     */
246    @Callable
247    public Map<String, Object> getCatalogsProperties(List<String> ids)
248    {
249        Map<String, Object> result = new HashMap<>();
250        
251        List<Map<String, Object>> catalogs = new LinkedList<>();
252        Set<String> unknownCatalogs = new HashSet<>();
253        
254        for (String id : ids)
255        {
256            try
257            {
258                Catalog catalog = _resolver.resolveById(id);
259                catalogs.add(getCatalogProperties(catalog));
260            }
261            catch (UnknownAmetysObjectException e)
262            {
263                unknownCatalogs.add(id);
264            }
265        }
266        
267        result.put("catalogs", catalogs);
268        result.put("unknownCatalogs", unknownCatalogs);
269        
270        return result;
271    }
272    
273    /**
274     * Generates the PDF of this catalog.
275     * @param name The name (code) of the catalog to export
276     * @param contextualParameters the contextual parameters
277     * @return An empty map, or an error
278     */
279    @Callable
280    public Map<String, Object> generatePDF(String name, Map<String, Object> contextualParameters)
281    {
282        Map<String, Object> result = new HashMap<>();
283        
284        if (GeneratePDFEngine.isRunning())
285        {
286            result.put("message", "already-running");
287        }
288        else
289        {
290            GeneratePDFEngine generatePDFEngine = new GeneratePDFEngine();
291            
292            UserIdentity identity = _currentUserProvider.getUser();
293            User currentUser = _userManager.getUser(identity.getPopulationId(), identity.getLogin());
294            
295            generatePDFEngine.setContextualParameters(contextualParameters);
296            generatePDFEngine.setCatalog(name);
297            generatePDFEngine.setIssuer(currentUser);
298            
299            try
300            {
301                // Initialize and configure the engine.
302                generatePDFEngine.initialize(_manager, _context);
303                
304                // Create the thread, mark it as daemon and start it.
305                Thread engineThread = new Thread(generatePDFEngine, "GeneratePDFEngine");
306                engineThread.setDaemon(true);
307                engineThread.start();
308            }
309            catch (Exception e)
310            {
311                throw new RuntimeException("Unable to initialize the generate pdf engine", e);
312            }
313        }
314        
315        return result;
316    }
317    
318    /**
319     * Get the properties of a catalog as a Map
320     * @param catalog The catalog
321     * @return The properties into a map object
322     */
323    public Map<String, Object> getCatalogProperties(Catalog catalog)
324    {
325        Map<String, Object> result = new HashMap<>();
326        
327        result.put("id", catalog.getId());
328        result.put("title", catalog.getTitle());
329        result.put("isDefault", catalog.isDefault());
330        result.put("code", catalog.getName());
331        
332        AmetysObjectIterable<Program> programs = _catalogsManager.getPrograms(catalog.getName());
333        result.put("nbPrograms", programs.getSize());
334        
335        return result;
336    }
337}