DamEventPurgeService.java 12.7 KB
/*
 * Decompiled with CFR 0_118.
 * 
 * Could not load the following classes:
 *  com.day.cq.dam.api.DamEvent
 *  com.day.cq.dam.api.DamEvent$Type
 *  javax.jcr.Node
 *  javax.jcr.Property
 *  javax.jcr.RepositoryException
 *  javax.jcr.Session
 *  org.apache.commons.lang.ArrayUtils
 *  org.apache.felix.scr.annotations.Activate
 *  org.apache.felix.scr.annotations.Component
 *  org.apache.felix.scr.annotations.Properties
 *  org.apache.felix.scr.annotations.Property
 *  org.apache.felix.scr.annotations.PropertyOption
 *  org.apache.felix.scr.annotations.PropertyUnbounded
 *  org.apache.felix.scr.annotations.Reference
 *  org.apache.felix.scr.annotations.Service
 *  org.apache.jackrabbit.commons.flat.TreeTraverser
 *  org.apache.sling.api.resource.LoginException
 *  org.apache.sling.api.resource.Resource
 *  org.apache.sling.api.resource.ResourceResolver
 *  org.apache.sling.api.resource.ResourceResolverFactory
 *  org.apache.sling.api.resource.ValueMap
 *  org.apache.sling.commons.osgi.OsgiUtil
 *  org.osgi.framework.BundleContext
 *  org.osgi.service.component.ComponentContext
 *  org.slf4j.Logger
 *  org.slf4j.LoggerFactory
 */
package com.day.cq.dam.core.impl;

import com.day.cq.dam.api.DamEvent;
import java.util.Collections;
import java.util.Dictionary;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Map;
import javax.jcr.Node;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import org.apache.commons.lang.ArrayUtils;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Properties;
import org.apache.felix.scr.annotations.Property;
import org.apache.felix.scr.annotations.PropertyOption;
import org.apache.felix.scr.annotations.PropertyUnbounded;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.Service;
import org.apache.jackrabbit.commons.flat.TreeTraverser;
import org.apache.sling.api.resource.LoginException;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.resource.ResourceResolverFactory;
import org.apache.sling.api.resource.ValueMap;
import org.apache.sling.commons.osgi.OsgiUtil;
import org.osgi.framework.BundleContext;
import org.osgi.service.component.ComponentContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Component(immediate=1, metatype=1, label="DAM Event Purge Service")
@Properties(value={@Property(name="scheduler.expression", value={"* * 23 * * ?"}), @Property(name="maxSavedActivities", label="Number of activities to keep under each user", intValue={150}), @Property(name="saveInterval", label="Save session state after deleting activities", description="Number of delete operations after which state of system should be saved", intValue={100}), @Property(name="enableActivityPurge", label="Enable purging of old activity record", description="This will enable the purging of user activities recorded by DamEventRecorder", boolValue={0}), @Property(name="scheduler.concurrent", boolValue={0}, propertyPrivate=1), @Property(name="eventTypes", unbounded=PropertyUnbounded.ARRAY, label="Select the activity types you want to purge", options={@PropertyOption(value="License accepted (ACCEPTED)", name="ACCEPTED"), @PropertyOption(value="Asset created (ASSET_CREATED)", name="ASSET_CREATED"), @PropertyOption(value="Asset moved (ASSET_MOVED)", name="ASSET_MOVED"), @PropertyOption(value="Asset removed (ASSET_REMOVED)", name="ASSET_REMOVED"), @PropertyOption(value="Asset expired (ASSET_EXPIRED)", name="ASSET_EXPIRED"), @PropertyOption(value="Asset expiring (ASSET_EXPIRING)", name="ASSET_EXPIRING"), @PropertyOption(value="License rejected (REJECTED)", name="REJECTED"), @PropertyOption(value="Asset downloaded (DOWNLOADED)", name="DOWNLOADED"), @PropertyOption(value="Asset versioned (VERSIONED)", name="VERSIONED"), @PropertyOption(value="Asset version restored (RESTORED)", name="RESTORED"), @PropertyOption(value="Asset Metadata updated (METADATA_UPDATED)", name="METADATA_UPDATED"), @PropertyOption(value="Asset published to external system (PUBLISHED_EXTERNAL)", name="PUBLISHED_EXTERNAL"), @PropertyOption(value="Asset's original updated (ORIGINAL_UPDATED)", name="ORIGINAL_UPDATED"), @PropertyOption(value="Asset Rendition updated (RENDITION_UPDATED)", name="RENDITION_UPDATED"), @PropertyOption(value="Asset Rendition removed (RENDITION_REMOVED)", name="RENDITION_REMOVED"), @PropertyOption(value="Sub-asset updated (SUBASSET_UPDATED)", name="SUBASSET_UPDATED"), @PropertyOption(value="Sub-asset removed (SUBASSET_REMOVED)", name="SUBASSET_REMOVED"), @PropertyOption(value="Asset Viewed (ASSET_VIEWED)", name="ASSET_VIEWED"), @PropertyOption(value="Asset Shared on Cloud Solutions (ASSET_SHARED)", name="ASSET_SHARED"), @PropertyOption(value="Asset Published (ASSET_PUBLISHED)", name="ASSET_PUBLISHED"), @PropertyOption(value="Project Viewed (PROJECT_VIEWED)", name="PROJECT_VIEWED"), @PropertyOption(value="Collection Viewed (COLLECTION_VIEWED)", name="COLLECTION_VIEWED"), @PropertyOption(value="Added Comment (ADDED_COMMENT)", name="ADDED_COMMENT")}, value={"ACCEPTED", "ASSET_CREATED", "ASSET_MOVED", "ASSET_REMOVED", "ASSET_EXPIRED", "ASSET_EXPIRING", "REJECTED", "VERSIONED", "RESTORED", "METADATA_UPDATED", "PUBLISHED_EXTERNAL", "ORIGINAL_UPDATED", "RENDITION_UPDATED", "RENDITION_REMOVED", "SUBASSET_REMOVED", "SUBASSET_UPDATED", "ASSET_VIEWED", "ASSET_SHARED", "ASSET_PUBLISHED", "ADDED_COMMENT", "PROJECT_VIEWED", "COLLECTION_VIEWED"})})
@Service(value={Runnable.class})
public class DamEventPurgeService
implements Runnable {
    private static final Logger LOGGER = LoggerFactory.getLogger(DamEventPurgeService.class);
    protected static final String ENABLE_ACTIVITY_PURGE = "enableActivityPurge";
    protected static final boolean DEFAULT_ENABLE_PURGE = false;
    private boolean enabled;
    protected static final String MAX_SAVED_ACTIVITIES = "maxSavedActivities";
    protected static final int MAX_ACTIVITIES_DEFAULT = 150;
    private int maxActivities;
    protected static final String SAVE_INTERVAL = "saveInterval";
    protected static final int SAVE_INTERVAL_DEFAULT = 100;
    private int saveInterval;
    protected static final String EVENT_TYPES = "eventTypes";
    private static final String[] DEFAULT_EVENT_TYPES = new String[]{DamEvent.Type.ACCEPTED.name(), DamEvent.Type.ASSET_CREATED.name(), DamEvent.Type.ASSET_MOVED.name(), DamEvent.Type.ASSET_REMOVED.name(), DamEvent.Type.ASSET_EXPIRED.name(), DamEvent.Type.ASSET_EXPIRING.name(), DamEvent.Type.REJECTED.name(), DamEvent.Type.VERSIONED.name(), DamEvent.Type.RESTORED.name(), DamEvent.Type.METADATA_UPDATED.name(), DamEvent.Type.PUBLISHED_EXTERNAL.name(), DamEvent.Type.ORIGINAL_UPDATED.name(), DamEvent.Type.RENDITION_UPDATED.name(), DamEvent.Type.RENDITION_REMOVED.name(), DamEvent.Type.SUBASSET_UPDATED.name(), DamEvent.Type.SUBASSET_REMOVED.name(), DamEvent.Type.ASSET_VIEWED.name(), DamEvent.Type.ASSET_SHARED.name(), DamEvent.Type.ASSET_PUBLISHED.name(), DamEvent.Type.ADDED_COMMENT.name(), DamEvent.Type.COLLECTION_VIEWED.name(), DamEvent.Type.PROJECT_VIEWED.name()};
    private static final String userHome = "/home/users";
    private static final String activityLocation = "activities/dam";
    private static final String propertyName = "verb";
    @Reference
    private ResourceResolverFactory resolverFactory = null;
    ResourceResolver serviceUserResolver = null;
    private String[] eventsToPurge;
    private int delCount = 0;
    private static final String USER_TYPE = "rep:User";
    private static final String FOLDER_TYPE = "rep:AuthorizableFolder";
    private Session session = null;

    @Activate
    protected void activate(BundleContext bundleContext, ComponentContext context) {
        this.enabled = OsgiUtil.toBoolean(context.getProperties().get("enableActivityPurge"), (boolean)false);
        this.maxActivities = OsgiUtil.toInteger(context.getProperties().get("maxSavedActivities"), (int)150);
        this.saveInterval = OsgiUtil.toInteger(context.getProperties().get("saveInterval"), (int)100);
        this.eventsToPurge = OsgiUtil.toStringArray(context.getProperties().get("eventTypes"), (String[])DEFAULT_EVENT_TYPES);
    }

    /*
     * WARNING - Removed try catching itself - possible behaviour change.
     */
    @Override
    public void run() {
        block11 : {
            if (!this.enabled) {
                return;
            }
            try {
                this.serviceUserResolver = this.resolverFactory.getServiceResourceResolver(Collections.singletonMap("sling.service.subservice", "activitypurgesrv"));
                this.session = (Session)this.serviceUserResolver.adaptTo(Session.class);
                Resource userDirectory = this.serviceUserResolver.getResource("/home/users");
                if (null == userDirectory) {
                    return;
                }
                this.traverseDirectory(userDirectory);
                if (this.delCount <= 0) break block11;
                try {
                    this.session.save();
                }
                catch (RepositoryException e) {
                    LOGGER.error("Could not save repository after deleting activities");
                }
            }
            catch (LoginException e) {
                LOGGER.error("Could not save repository after deleting activities");
            }
            finally {
                if (this.serviceUserResolver != null) {
                    this.serviceUserResolver.close();
                    this.serviceUserResolver = null;
                }
            }
        }
    }

    private void traverseDirectory(Resource directory) {
        Iterator children = directory.listChildren();
        while (children.hasNext()) {
            Resource child = (Resource)children.next();
            ValueMap childProp = (ValueMap)child.adaptTo(ValueMap.class);
            String childType = (String)childProp.get("jcr:primaryType", (Object)"");
            if ("rep:User".equals(childType)) {
                this.traverseUser(child);
                continue;
            }
            if (!"rep:AuthorizableFolder".equals(childType)) continue;
            this.traverseDirectory(child);
        }
    }

    private void traverseUser(Resource user) {
        LinkedList<String> activityPath = new LinkedList<String>();
        activityPath.clear();
        Resource activities = user.getChild("activities/dam");
        if (null != activities) {
            TreeTraverser traverser = new TreeTraverser((Node)activities.adaptTo(Node.class));
            for (Node activity : traverser) {
                try {
                    if (!activity.hasProperty("verb") || !ArrayUtils.contains((Object[])this.eventsToPurge, (Object)activity.getProperty("verb").getString())) continue;
                    activityPath.addLast(activity.getPath());
                    if (activityPath.size() <= this.maxActivities) continue;
                    try {
                        Resource activityFolder = this.serviceUserResolver.getResource((String)activityPath.getFirst()).getParent();
                        this.session.removeItem((String)activityPath.getFirst());
                        this.delCount += this.deleteEmptyFolder(activityFolder);
                        ++this.delCount;
                    }
                    catch (RepositoryException e) {
                        LOGGER.error("Unable to delete item at " + (String)activityPath.getFirst());
                    }
                    activityPath.removeFirst();
                    if (this.delCount < this.saveInterval) continue;
                    try {
                        this.session.save();
                    }
                    catch (RepositoryException e) {
                        LOGGER.error("Could not save repository after deleting activities");
                    }
                    this.delCount = 0;
                }
                catch (RepositoryException e) {
                    LOGGER.error("Could not read node from repository");
                }
            }
        }
    }

    private int deleteEmptyFolder(Resource folder) throws RepositoryException {
        Resource parentFolder = folder.getParent();
        Iterator folderIterator = folder.listChildren();
        if (folderIterator != null && !folderIterator.hasNext()) {
            this.session.removeItem(folder.getPath());
            return this.deleteEmptyFolder(parentFolder) + 1;
        }
        return 0;
    }

    protected void bindResolverFactory(ResourceResolverFactory resourceResolverFactory) {
        this.resolverFactory = resourceResolverFactory;
    }

    protected void unbindResolverFactory(ResourceResolverFactory resourceResolverFactory) {
        if (this.resolverFactory == resourceResolverFactory) {
            this.resolverFactory = null;
        }
    }
}