001/*
002 *  Copyright 2010 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.newsletter.category;
017
018import java.util.ArrayList;
019import java.util.Arrays;
020import java.util.Collection;
021import java.util.List;
022
023import org.apache.avalon.framework.configuration.Configurable;
024import org.apache.avalon.framework.configuration.Configuration;
025import org.apache.avalon.framework.configuration.ConfigurationException;
026import org.apache.avalon.framework.logger.LogEnabled;
027import org.apache.avalon.framework.logger.Logger;
028import org.apache.avalon.framework.service.ServiceException;
029import org.apache.avalon.framework.service.ServiceManager;
030import org.apache.avalon.framework.service.Serviceable;
031
032import org.ametys.cms.repository.Content;
033import org.ametys.cms.repository.ContentTypeExpression;
034import org.ametys.plugins.repository.AmetysObjectIterable;
035import org.ametys.plugins.repository.AmetysObjectResolver;
036import org.ametys.plugins.repository.UnknownAmetysObjectException;
037import org.ametys.plugins.repository.query.expression.AndExpression;
038import org.ametys.plugins.repository.query.expression.Expression;
039import org.ametys.plugins.repository.query.expression.Expression.Operator;
040import org.ametys.plugins.repository.query.expression.StringExpression;
041import org.ametys.runtime.i18n.I18nizableText;
042import org.ametys.runtime.plugin.component.PluginAware;
043import org.ametys.web.repository.page.ModifiablePage;
044import org.ametys.web.repository.page.Page;
045import org.ametys.web.repository.page.PageQueryHelper;
046import org.ametys.web.repository.page.jcr.DefaultPage;
047import org.ametys.web.tags.TagExpression;
048
049/**
050 * This class provides newsletter categories from the site map
051 *
052 */
053public class SitemapCategoryProvider implements LogEnabled, CategoryProvider, Serviceable, Configurable, PluginAware
054{
055    /** The root id */
056    public static final String TAG_NAME = "NEWSLETTER_CATEGORY";
057    /** The metadata name for newsletter template */
058    public static final String METADATA_TEMPLATE = "newsletterTemplate";
059    /** The metadata name for automatic newsletter ids. */
060    public static final String METADATA_AUTOMATIC_IDS = "newsletterAutomaticIds";
061    /** The metadata name for newsletter template */
062    public static final String CATEGORY_PREFIX_ID = "category_";
063    
064    /** The id */
065    protected String _id;
066    /** The label */
067    protected I18nizableText _label;
068    /** The description */
069    protected I18nizableText _description;
070    /** The plugin name */
071    protected String _pluginName;
072    /** The feature name */
073    protected String _featureName;
074
075    /** The Logger */
076    protected Logger _logger;
077    
078    private AmetysObjectResolver _resolver;
079
080    @Override
081    public void service(ServiceManager serviceManager) throws ServiceException
082    {
083        _resolver = (AmetysObjectResolver) serviceManager.lookup(AmetysObjectResolver.ROLE);
084    }
085    
086    @Override
087    public void configure(Configuration configuration) throws ConfigurationException
088    {
089        _label = configureLabel(configuration);
090        _description = configureDescription(configuration);
091    }
092    
093    public void enableLogging(Logger logger)
094    {
095        _logger = logger;
096    }
097    
098    @Override
099    public boolean isWritable()
100    {
101        return false;
102    }
103    
104    @Override
105    public List<Category> getCategories(String siteName, String lang)
106    {
107        TagExpression expr = new TagExpression(Operator.EQ, TAG_NAME);
108        String xpathQuery = PageQueryHelper.getPageXPathQuery(siteName, lang, "", expr, null);
109        
110        List<Category> categories = new ArrayList<>();
111        
112        AmetysObjectIterable<DefaultPage> pages = _resolver.query(xpathQuery);
113        for (DefaultPage page : pages)
114        {
115            Category category = new Category(CATEGORY_PREFIX_ID + page.getId(), page.getName(), _id, new I18nizableText(page.getTitle()), null, page.getMetadataHolder().getString(METADATA_TEMPLATE, null), siteName, lang);
116            categories.add(category);
117        }
118        
119        return categories;
120    }
121    
122    @Override
123    public Collection<Category> getAllCategories(String siteName, String lang)
124    {
125        return getCategories(siteName, lang);
126    }
127    
128    @Override
129    public List<Category> getCategories(String categoryID)
130    {
131        return new ArrayList<>();
132    }
133
134    @Override
135    public boolean hasCategory(String categoryID)
136    {
137        if (categoryID.startsWith(CATEGORY_PREFIX_ID))
138        {
139            String pageID = categoryID.substring(CATEGORY_PREFIX_ID.length());
140            try
141            {
142                DefaultPage page = _resolver.resolveById(pageID);
143                if (page != null)
144                {
145                    return page.getTags().contains(TAG_NAME);
146                }
147            }
148            catch (UnknownAmetysObjectException e)
149            {
150                // Page does not exist anymore
151                return false;
152            }
153        }
154        return false;
155    }
156    
157    @Override
158    public Category getCategory(String categoryID)
159    {
160        if (categoryID.startsWith("category_"))
161        {
162            String pageID = categoryID.substring(CATEGORY_PREFIX_ID.length());
163            DefaultPage page = _resolver.resolveById(pageID);
164            if (page != null && page.getTags().contains(TAG_NAME))
165            {
166                return new Category(CATEGORY_PREFIX_ID + page.getId(), page.getName(), "provider_" + _id, new I18nizableText(page.getTitle()), new I18nizableText(""), page.getMetadataHolder().getString(METADATA_TEMPLATE, null), page.getSiteName(), page.getSitemapName());
167            }
168        }
169        return null;
170    }
171    
172    @Override
173    public void setTemplate(Category category, String templateName)
174    {
175        String categoryID = category.getId();
176        if (categoryID.startsWith("category_"))
177        {
178            String pageID = categoryID.substring(CATEGORY_PREFIX_ID.length());
179            ModifiablePage page = _resolver.resolveById(pageID);
180            if (page != null)
181            {
182                page.getMetadataHolder().setMetadata(METADATA_TEMPLATE, templateName);
183                page.saveChanges();
184            }
185        }
186    }
187    
188    @Override
189    public Collection<String> getAutomaticIds(String categoryId)
190    {
191        if (categoryId.startsWith("category_"))
192        {
193            String pageID = categoryId.substring(CATEGORY_PREFIX_ID.length());
194            Page page = _resolver.resolveById(pageID);
195            if (page != null)
196            {
197                String[] autoIds = page.getMetadataHolder().getStringArray(METADATA_AUTOMATIC_IDS, new String[0]);
198                
199                return Arrays.asList(autoIds);
200            }
201        }
202        
203        // Either the category ID is not a page category, or the page doesn't exist.
204        throw new IllegalArgumentException("The provided category ID is invalid.");
205    }
206    
207    @Override
208    public void setAutomatic(String categoryId, Collection<String> automaticNewsletterIds)
209    {
210        if (categoryId.startsWith("category_"))
211        {
212            String pageID = categoryId.substring(CATEGORY_PREFIX_ID.length());
213            Page page = _resolver.resolveById(pageID);
214            if (page != null && page instanceof ModifiablePage)
215            {
216                ModifiablePage modifiablePage = (ModifiablePage) page;
217                
218                // Convert to array.
219                String[] autoIdsArray = automaticNewsletterIds.toArray(new String[automaticNewsletterIds.size()]);
220                                
221                modifiablePage.getMetadataHolder().setMetadata(METADATA_AUTOMATIC_IDS, autoIdsArray);
222                modifiablePage.saveChanges();
223                
224                return;
225            }
226        }
227        
228        // Either the category ID is not a page category, or the page doesn't exist.
229        throw new IllegalArgumentException("The provided category ID is invalid.");
230    }
231    
232    @Override
233    public AmetysObjectIterable<Content> getNewsletters(String categoryID, String siteName, String lang)
234    {
235        Expression cTypeExpr = new ContentTypeExpression(Operator.EQ, "org.ametys.plugins.newsletter.Content.newsletter");
236        Expression siteExpr = new StringExpression("site", Operator.EQ, siteName);
237        Expression catExpr = new StringExpression("category", Operator.EQ, categoryID);
238        Expression expr = new AndExpression(cTypeExpr, siteExpr, catExpr);
239        
240        String xpathQuery = org.ametys.plugins.repository.query.QueryHelper.getXPathQuery(null, "ametys:content", expr);
241        return _resolver.query(xpathQuery);
242    }
243    
244    @Override
245    public boolean hasChildren(String categoryID)
246    {
247        return false;
248    }
249
250    @Override
251    public boolean hasNewsletters(String categoryID, String siteName, String lang)
252    {
253        Expression expr = new ContentTypeExpression(Operator.EQ, "org.ametys.plugins.newsletter.Content.newsletter");
254        Expression siteExpr = new StringExpression("site", Operator.EQ, siteName);
255        expr = new AndExpression(expr, siteExpr);
256        Expression catExpr = new StringExpression("category", Operator.EQ, categoryID);
257        expr = new AndExpression(expr, catExpr);
258        
259        String xpathQuery = org.ametys.plugins.repository.query.QueryHelper.getXPathQuery(null, "ametys:content", expr);
260        
261        return _resolver.query(xpathQuery).iterator().hasNext();
262    }
263    
264    /**
265     * Configure label from the passed configuration
266     * @param configuration The configuration
267     * @return The label
268     * @throws ConfigurationException If an error occurred
269     */
270    protected I18nizableText configureLabel (Configuration configuration) throws ConfigurationException
271    {
272        Configuration labelConfiguration = configuration.getChild("label");
273        
274        if (labelConfiguration.getAttributeAsBoolean("i18n", false))
275        {
276            return new I18nizableText("plugin." + _pluginName, labelConfiguration.getValue(""));
277        }
278        else
279        {
280            return new I18nizableText(labelConfiguration.getValue(""));
281        }
282    }
283    
284    /**
285     * Configure description from the passed configuration
286     * @param configuration The configuration
287     * @return The description
288     * @throws ConfigurationException If an error occurred
289     */
290    protected I18nizableText configureDescription (Configuration configuration) throws ConfigurationException
291    {
292        Configuration descConfiguration = configuration.getChild("description");
293        
294        if (descConfiguration.getAttributeAsBoolean("i18n", false))
295        {
296            return new I18nizableText("plugin." + _pluginName, descConfiguration.getValue(""));
297        }
298        else
299        {
300            return new I18nizableText(descConfiguration.getValue(""));
301        }
302    }
303    
304    public void setPluginInfo(String pluginName, String featureName, String id)
305    {
306        _pluginName = pluginName;
307        _featureName = featureName;
308        _id = id;
309    }
310    
311    /**
312     * Get the plugin name
313     * @return the plugin name
314     */
315    public String getPluginName()
316    {
317        return _pluginName;
318    }
319
320    @Override
321    public I18nizableText getDescription()
322    {
323        return _description;
324    }
325
326    @Override
327    public String getId()
328    {
329        return _id;
330    }
331
332    @Override
333    public I18nizableText getLabel()
334    {
335        return _label;
336    }
337
338    @Override
339    public String getRootId(String siteName, String lang)
340    {
341        return _id;
342    }
343}