001/*
002 * This library is part of OpenCms -
003 * the Open Source Content Management System
004 *
005 * Copyright (c) Alkacon Software GmbH & Co. KG (http://www.alkacon.com)
006 *
007 * This library is free software; you can redistribute it and/or
008 * modify it under the terms of the GNU Lesser General Public
009 * License as published by the Free Software Foundation; either
010 * version 2.1 of the License, or (at your option) any later version.
011 *
012 * This library is distributed in the hope that it will be useful,
013 * but WITHOUT ANY WARRANTY; without even the implied warranty of
014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015 * Lesser General Public License for more details.
016 *
017 * For further information about Alkacon Software, please see the
018 * company website: http://www.alkacon.com
019 *
020 * For further information about OpenCms, please see the
021 * project website: http://www.opencms.org
022 *
023 * You should have received a copy of the GNU Lesser General Public
024 * License along with this library; if not, write to the Free Software
025 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
026 */
027
028package org.opencms.db;
029
030import org.opencms.file.CmsGroup;
031import org.opencms.file.CmsObject;
032import org.opencms.file.CmsResource;
033import org.opencms.file.CmsResourceFilter;
034import org.opencms.file.CmsUser;
035import org.opencms.file.history.I_CmsHistoryResource;
036import org.opencms.main.CmsException;
037import org.opencms.main.CmsRuntimeException;
038import org.opencms.main.OpenCms;
039import org.opencms.security.CmsPrincipal;
040import org.opencms.security.CmsRole;
041import org.opencms.security.CmsRoleViolationException;
042import org.opencms.util.CmsStringUtil;
043
044import java.util.List;
045
046/**
047 * Manager that provides methods to subscribe resources to users, read subscribed or unvisited resources and more.<p>
048 *
049 * @since 8.0
050 */
051public class CmsSubscriptionManager {
052
053    /** The default maximum number of visited resources to store per user. */
054    private static final int DEFAULT_MAX_VISITEDCOUNT = 1000;
055
056    /** The security manager to access the cms. */
057    protected CmsSecurityManager m_securityManager;
058
059    /** Indicates if the subscription functionality is enabled. */
060    private boolean m_enabled;
061
062    /** Indicates if the configuration can be modified. */
063    private boolean m_frozen;
064
065    /** The maximum number of visited resources to store per user. */
066    private int m_maxVisitedCount;
067
068    /** The name of the database pool to use. */
069    private String m_poolName;
070
071    /**
072     * Initializes a new CmsSubscriptionManager, called from the configuration.<p>
073     */
074    public CmsSubscriptionManager() {
075
076        m_frozen = false;
077    }
078
079    /**
080     * Returns the date when the resource was last visited by the user.<p>
081     *
082     * @param cms the current users context
083     * @param user the user to check the date
084     * @param resource the resource to check the date
085     *
086     * @return the date when the resource was last visited by the user
087     *
088     * @throws CmsException if something goes wrong
089     */
090    public long getDateLastVisitedBy(CmsObject cms, CmsUser user, CmsResource resource) throws CmsException {
091
092        return m_securityManager.getDateLastVisitedBy(cms.getRequestContext(), getPoolName(), user, resource);
093    }
094
095    /**
096     * Returns the date when the resource was last visited by the user.<p>
097     *
098     * @param cms the current users context
099     * @param user the user to check the date
100     * @param resourcePath the name of the resource to check the date
101     *
102     * @return the date when the resource was last visited by the user
103     *
104     * @throws CmsException if something goes wrong
105     */
106    public long getDateLastVisitedBy(CmsObject cms, CmsUser user, String resourcePath) throws CmsException {
107
108        CmsResource resource = cms.readResource(resourcePath, CmsResourceFilter.ALL);
109        return m_securityManager.getDateLastVisitedBy(cms.getRequestContext(), getPoolName(), user, resource);
110    }
111
112    /**
113     * Returns the maximum number of visited resources to store per user.<p>
114     *
115     * @return the maximum number of visited resources to store per user
116     */
117    public int getMaxVisitedCount() {
118
119        if (m_maxVisitedCount < 1) {
120            m_maxVisitedCount = DEFAULT_MAX_VISITEDCOUNT;
121        }
122        return m_maxVisitedCount;
123    }
124
125    /**
126     * Returns the name of the database pool to use.<p>
127     *
128     * @return the name of the database pool to use
129     */
130    public String getPoolName() {
131
132        if (CmsStringUtil.isEmpty(m_poolName)) {
133            // use default pool as pool name
134            m_poolName = OpenCms.getSqlManager().getDefaultDbPoolName();
135        }
136        return m_poolName;
137    }
138
139    /**
140     * Initializes this subscription manager with the OpenCms system configuration.<p>
141     *
142     * @param cms an OpenCms context object that must have been initialized with "Admin" permissions
143     *
144     * @throws CmsRoleViolationException in case the given opencms object does not have <code>{@link CmsRole#ROOT_ADMIN}</code> permissions
145     */
146    public void initialize(CmsObject cms) throws CmsRoleViolationException {
147
148        OpenCms.getRoleManager().checkRole(cms, CmsRole.ROOT_ADMIN);
149        m_frozen = true;
150    }
151
152    /**
153     * Returns if the subscription functionality is enabled.<p>
154     *
155     * @return <code>true</code> if the subscription functionality is enabled, otherwise <code>false</code>
156     */
157    public boolean isEnabled() {
158
159        return m_enabled && (m_securityManager != null) && m_securityManager.isSubscriptionDriverAvailable();
160    }
161
162    /**
163     * Mark the given resource as visited by the user.<p>
164     *
165     * @param cms the current users context
166     * @param resource the resource to mark as visited
167     * @param user the user that visited the resource
168     *
169     * @throws CmsException if something goes wrong
170     */
171    public void markResourceAsVisitedBy(CmsObject cms, CmsResource resource, CmsUser user) throws CmsException {
172
173        if (!isEnabled()) {
174            throw new CmsRuntimeException(Messages.get().container(Messages.ERR_SUBSCRIPTION_MANAGER_DISABLED_0));
175        }
176        m_securityManager.markResourceAsVisitedBy(cms.getRequestContext(), getPoolName(), resource, user);
177    }
178
179    /**
180     * Mark the given resource as visited by the user.<p>
181     *
182     * @param cms the current users context
183     * @param resourcePath the name of the resource to mark as visited
184     * @param user the user that visited the resource
185     *
186     * @throws CmsException if something goes wrong
187     */
188    public void markResourceAsVisitedBy(CmsObject cms, String resourcePath, CmsUser user) throws CmsException {
189
190        CmsResource resource = cms.readResource(resourcePath, CmsResourceFilter.ALL);
191        markResourceAsVisitedBy(cms, resource, user);
192    }
193
194    /**
195     * Returns all resources subscribed by the given user or group.<p>
196     *
197     * @param cms the current users context
198     * @param principal the principal to read the subscribed resources
199     *
200     * @return all resources subscribed by the given user or group
201     *
202     * @throws CmsException if something goes wrong
203     */
204    public List<CmsResource> readAllSubscribedResources(CmsObject cms, CmsPrincipal principal) throws CmsException {
205
206        return m_securityManager.readAllSubscribedResources(cms.getRequestContext(), getPoolName(), principal);
207    }
208
209    /**
210     * Returns the resources that were visited by a user set in the filter.<p>
211     *
212     * @param cms the current users context
213     * @param filter the filter that is used to get the visited resources
214     *
215     * @return the resources that were visited by a user set in the filter
216     *
217     * @throws CmsException if something goes wrong
218     */
219    public List<CmsResource> readResourcesVisitedBy(CmsObject cms, CmsVisitedByFilter filter) throws CmsException {
220
221        return m_securityManager.readResourcesVisitedBy(cms.getRequestContext(), getPoolName(), filter);
222    }
223
224    /**
225     * Returns the subscribed history resources that were deleted.<p>
226     *
227     * @param cms the current users context
228     * @param user the user that subscribed to the resource
229     * @param includeGroups indicates if the users groups should also be checked for subscribed deleted resources
230     * @param folderPath the folder path of the deleted resources, if <code>null</code> all deleted resources will be returned
231     * @param includeSubFolders indicates if the sub folders of the specified folder path should be considered, too
232     * @param deletedFrom the time stamp from which the resources should have been deleted
233     *
234     * @return the subscribed history resources that were deleted
235     *
236     * @throws CmsException if something goes wrong
237     */
238    public List<I_CmsHistoryResource> readSubscribedDeletedResources(
239        CmsObject cms,
240        CmsUser user,
241        boolean includeGroups,
242        String folderPath,
243        boolean includeSubFolders,
244        long deletedFrom) throws CmsException {
245
246        List<CmsGroup> groups = null;
247        if (includeGroups) {
248            try {
249                groups = cms.getGroupsOfUser(user.getName(), false);
250            } catch (CmsException e) {
251                // failed to set user groups
252            }
253        }
254        CmsResource resource = null;
255        if (CmsStringUtil.isNotEmpty(folderPath)) {
256            resource = cms.readResource(folderPath, CmsResourceFilter.ALL);
257        }
258        return m_securityManager.readSubscribedDeletedResources(
259            cms.getRequestContext(),
260            getPoolName(),
261            user,
262            groups,
263            resource,
264            includeSubFolders,
265            deletedFrom);
266    }
267
268    /**
269     * Returns the resources that were subscribed by a user or group set in the filter.<p>
270     *
271     * @param cms the current users context
272     * @param filter the filter that is used to get the subscribed resources
273     *
274     * @return the resources that were subscribed by a user or group set in the filter
275     *
276     * @throws CmsException if something goes wrong
277     */
278    public List<CmsResource> readSubscribedResources(CmsObject cms, CmsSubscriptionFilter filter) throws CmsException {
279
280        return m_securityManager.readSubscribedResources(cms.getRequestContext(), getPoolName(), filter);
281    }
282
283    /**
284     * Sets if the subscription functionality is enabled.<p>
285     *
286     * @param enabled the flag indicating if the subscription functionality is enabled
287     */
288    public void setEnabled(boolean enabled) {
289
290        if (m_frozen) {
291            throw new CmsRuntimeException(Messages.get().container(Messages.ERR_CONFIG_SUBSCRIPTIONMANAGER_FROZEN_0));
292        }
293        m_enabled = enabled;
294    }
295
296    /**
297     * Sets if the subscription functionality is enabled.<p>
298     *
299     * @param enabled the flag indicating if the subscription functionality is enabled
300     */
301    public void setEnabled(String enabled) {
302
303        if (m_frozen) {
304            throw new CmsRuntimeException(Messages.get().container(Messages.ERR_CONFIG_SUBSCRIPTIONMANAGER_FROZEN_0));
305        }
306        m_enabled = Boolean.valueOf(enabled).booleanValue();
307    }
308
309    /**
310     * Sets the maximum number of visited resources to store per user.<p>
311     *
312     * @param maxVisitedCount the maximum number of visited resources to store per user
313     */
314    public void setMaxVisitedCount(String maxVisitedCount) {
315
316        if (m_frozen) {
317            throw new CmsRuntimeException(Messages.get().container(Messages.ERR_CONFIG_SUBSCRIPTIONMANAGER_FROZEN_0));
318        }
319        try {
320            int intValue = Integer.parseInt(maxVisitedCount);
321            m_maxVisitedCount = (intValue > 0) ? intValue : DEFAULT_MAX_VISITEDCOUNT;
322        } catch (NumberFormatException e) {
323            // use default value
324            m_maxVisitedCount = DEFAULT_MAX_VISITEDCOUNT;
325        }
326    }
327
328    /**
329     * Sets the name of the database pool to use.<p>
330     *
331     * @param poolName the name of the database pool to use
332     */
333    public void setPoolName(String poolName) {
334
335        if (m_frozen) {
336            throw new CmsRuntimeException(Messages.get().container(Messages.ERR_CONFIG_SUBSCRIPTIONMANAGER_FROZEN_0));
337        }
338        m_poolName = poolName;
339    }
340
341    /**
342     * Sets the security manager during initialization.<p>
343     *
344     * @param securityManager the security manager
345     */
346    public void setSecurityManager(CmsSecurityManager securityManager) {
347
348        if (m_frozen) {
349            throw new CmsRuntimeException(Messages.get().container(Messages.ERR_CONFIG_SUBSCRIPTIONMANAGER_FROZEN_0));
350        }
351        m_securityManager = securityManager;
352    }
353
354    /**
355     * Marks a subscribed resource as deleted.<p>
356     *
357     * @param cms the current users context
358     * @param resource the subscribed resource to mark as deleted
359     *
360     * @throws CmsException if something goes wrong
361     */
362    public void setSubscribedResourceAsDeleted(CmsObject cms, CmsResource resource) throws CmsException {
363
364        if (!isEnabled()) {
365            throw new CmsRuntimeException(Messages.get().container(Messages.ERR_SUBSCRIPTION_MANAGER_DISABLED_0));
366        }
367        m_securityManager.setSubscribedResourceAsDeleted(cms.getRequestContext(), getPoolName(), resource);
368    }
369
370    /**
371     * Subscribes the user or group to the resource.<p>
372     *
373     * @param cms the current users context
374     * @param principal the principal that subscribes to the resource
375     * @param resource the resource to subscribe to
376     *
377     * @throws CmsException if something goes wrong
378     */
379    public void subscribeResourceFor(CmsObject cms, CmsPrincipal principal, CmsResource resource) throws CmsException {
380
381        if (!isEnabled()) {
382            throw new CmsRuntimeException(Messages.get().container(Messages.ERR_SUBSCRIPTION_MANAGER_DISABLED_0));
383        }
384        m_securityManager.subscribeResourceFor(cms.getRequestContext(), getPoolName(), principal, resource);
385    }
386
387    /**
388     * Subscribes the user or group to the resource.<p>
389     *
390     * @param cms the current users context
391     * @param principal the principal that subscribes to the resource
392     * @param resourcePath the name of the resource to subscribe to
393     *
394     * @throws CmsException if something goes wrong
395     */
396    public void subscribeResourceFor(CmsObject cms, CmsPrincipal principal, String resourcePath) throws CmsException {
397
398        CmsResource resource = cms.readResource(resourcePath, CmsResourceFilter.ALL);
399        subscribeResourceFor(cms, principal, resource);
400    }
401
402    /**
403     * Unsubscribes all deleted resources that were deleted before the specified time stamp.<p>
404     *
405     * @param cms the current users context
406     * @param deletedTo the time stamp to which the resources have been deleted
407     *
408     * @throws CmsException if something goes wrong
409     */
410    public void unsubscribeAllDeletedResources(CmsObject cms, long deletedTo) throws CmsException {
411
412        if (!isEnabled()) {
413            throw new CmsRuntimeException(Messages.get().container(Messages.ERR_SUBSCRIPTION_MANAGER_DISABLED_0));
414        }
415        m_securityManager.unsubscribeAllDeletedResources(cms.getRequestContext(), getPoolName(), deletedTo);
416    }
417
418    /**
419    * Unsubscribes the user or group from all resources.<p>
420    *
421    * @param cms the current users context
422    * @param principal the principal that unsubscribes from all resources
423    *
424    * @throws CmsException if something goes wrong
425    */
426    public void unsubscribeAllResourcesFor(CmsObject cms, CmsPrincipal principal) throws CmsException {
427
428        if (!isEnabled()) {
429            throw new CmsRuntimeException(Messages.get().container(Messages.ERR_SUBSCRIPTION_MANAGER_DISABLED_0));
430        }
431        m_securityManager.unsubscribeAllResourcesFor(cms.getRequestContext(), getPoolName(), principal);
432    }
433
434    /**
435     * Unsubscribes the principal from the resource.<p>
436     *
437     * @param cms the current users context
438     * @param principal the principal that unsubscribes from the resource
439     * @param resource the resource to unsubscribe from
440     *
441     * @throws CmsException if something goes wrong
442     */
443    public void unsubscribeResourceFor(CmsObject cms, CmsPrincipal principal, CmsResource resource)
444    throws CmsException {
445
446        if (!isEnabled()) {
447            throw new CmsRuntimeException(Messages.get().container(Messages.ERR_SUBSCRIPTION_MANAGER_DISABLED_0));
448        }
449        m_securityManager.unsubscribeResourceFor(cms.getRequestContext(), getPoolName(), principal, resource);
450    }
451
452    /**
453     * Unsubscribes the principal from the resource.<p>
454     *
455     * @param cms the current users context
456     * @param principal the principal that unsubscribes from the resource
457     * @param resourcePath the name of the resource to unsubscribe from
458     *
459     * @throws CmsException if something goes wrong
460     */
461    public void unsubscribeResourceFor(CmsObject cms, CmsPrincipal principal, String resourcePath) throws CmsException {
462
463        CmsResource resource = cms.readResource(resourcePath, CmsResourceFilter.ALL);
464        unsubscribeResourceFor(cms, principal, resource);
465    }
466
467    /**
468     * Unsubscribes all groups and users from the resource.<p>
469     *
470     * @param cms the current users context
471     * @param resource the resource to unsubscribe all groups and users from
472     *
473     * @throws CmsException if something goes wrong
474     */
475    public void unsubscribeResourceForAll(CmsObject cms, CmsResource resource) throws CmsException {
476
477        if (!isEnabled()) {
478            throw new CmsRuntimeException(Messages.get().container(Messages.ERR_SUBSCRIPTION_MANAGER_DISABLED_0));
479        }
480        m_securityManager.unsubscribeResourceForAll(cms.getRequestContext(), getPoolName(), resource);
481    }
482
483    /**
484     * Unsubscribes all groups and users from the resource.<p>
485     *
486     * @param cms the current users context
487     * @param resourcePath the name of the resource to unsubscribe all groups and users from
488     *
489     * @throws CmsException if something goes wrong
490     */
491    public void unsubscribeResourceForAll(CmsObject cms, String resourcePath) throws CmsException {
492
493        CmsResource resource = cms.readResource(resourcePath, CmsResourceFilter.ALL);
494        unsubscribeResourceForAll(cms, resource);
495    }
496
497}