org.riotfamily.media.cleanup.HibernateCleanUpTask.java Source code

Java tutorial

Introduction

Here is the source code for org.riotfamily.media.cleanup.HibernateCleanUpTask.java

Source

/* Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.riotfamily.media.cleanup;

import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.engine.SessionFactoryImplementor;
import org.hibernate.metadata.ClassMetadata;
import org.hibernate.type.CollectionType;
import org.hibernate.type.ComponentType;
import org.hibernate.type.EntityType;
import org.hibernate.type.Type;
import org.riotfamily.common.scheduling.HibernateTask;
import org.riotfamily.common.util.Generics;
import org.riotfamily.media.model.RiotFile;
import org.riotfamily.media.store.FileStore;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallback;
import org.springframework.transaction.support.TransactionTemplate;

public class HibernateCleanUpTask extends HibernateTask {

    private Logger log = LoggerFactory.getLogger(HibernateCleanUpTask.class);

    private FileStore fileStore;

    private TransactionTemplate transactionTemplate;

    private List<String> fileQueries = Generics.newArrayList();

    public HibernateCleanUpTask(SessionFactory sessionFactory, FileStore fileStore, PlatformTransactionManager tx) {

        super(sessionFactory);
        this.fileStore = fileStore;
        this.transactionTemplate = new TransactionTemplate(tx);
        init();
    }

    @Override
    @SuppressWarnings("unchecked")
    protected void doWithoutResult(final Session session) throws Exception {

        log.info("Looking for orphaned files ...");

        List<Long> fileIds = session.createQuery("select id from " + RiotFile.class.getName()).list();

        Set<Long> referencedIds = Generics.newHashSet();
        for (String hql : fileQueries) {
            log.info(hql);
            referencedIds.addAll(session.createQuery(hql).list());
        }

        log.info("Deleting [{}] orphaned files ...", fileIds.size() - referencedIds.size());

        for (Long id : fileIds) {
            if (!referencedIds.contains(id)) {
                delete(session, id);
            }
        }

        log.info("Deleting unmanaged files ...");
        Iterator<String> files = fileStore.iterator();
        while (files.hasNext()) {
            String uri = files.next();
            if (!fileExists(session, uri)) {
                log.debug("Deleting unmanaged file: " + uri);
                files.remove();
            }
        }

        log.info("Media clean-up finished.");
    }

    private void delete(final Session session, final Long id) {
        try {
            RiotFile file = transactionTemplate.execute(new TransactionCallback<RiotFile>() {
                public RiotFile doInTransaction(TransactionStatus status) {
                    log.debug("Deleting orphaned file: " + id);
                    RiotFile file = (RiotFile) session.load(RiotFile.class, id);
                    session.delete(file);
                    return file;
                }
            });
            session.evict(file);
        } catch (HibernateException e) {
            log.error("Failed to delete RiotFile " + id, e);
        }
    }

    public boolean fileExists(Session session, String uri) {
        return session.createQuery("select id from " + RiotFile.class.getName() + " where uri = :uri")
                .setParameter("uri", uri).uniqueResult() != null;
    }

    @SuppressWarnings("unchecked")
    private void init() {
        Collection<ClassMetadata> allMeta = getSessionFactory().getAllClassMetadata().values();
        for (ClassMetadata meta : allMeta) {
            for (String name : meta.getPropertyNames()) {
                Type type = meta.getPropertyType(name);
                if (RiotFile.class.isAssignableFrom(type.getReturnedClass())) {
                    fileQueries.add(String.format("select %1$s.id from %2$s where %1$s is not null", name,
                            meta.getEntityName()));
                } else if (type instanceof ComponentType) {
                    handleComponentType((ComponentType) type, name, meta.getEntityName());
                } else if (type instanceof CollectionType) {
                    CollectionType collectionType = (CollectionType) type;
                    Type elementType = collectionType
                            .getElementType((SessionFactoryImplementor) getSessionFactory());

                    if (RiotFile.class.isAssignableFrom(elementType.getReturnedClass())) {
                        fileQueries.add(String.format(
                                "select file.id from %1$s ref " + "join ref.%2$s as file where file is not null",
                                meta.getEntityName(), name));
                    } else if (elementType instanceof ComponentType) {
                        handleCollectionComponentType((ComponentType) elementType, null, name,
                                meta.getEntityName());
                    }
                }
            }
        }
    }

    private void handleComponentType(ComponentType componentType, String property, String entityName) {

        for (int i = 0; i < componentType.getSubtypes().length; i++) {
            Type subtype = componentType.getSubtypes()[i];
            String subProperty = property + "." + componentType.getPropertyNames()[i];
            if (subtype instanceof EntityType && RiotFile.class.isAssignableFrom(subtype.getReturnedClass())) {

                fileQueries.add(
                        String.format("select %1$s.id from %2$s where %1$s is not null", subProperty, entityName));
            } else if (subtype.isComponentType()) {
                handleComponentType((ComponentType) subtype, subProperty, entityName);
            }
        }
    }

    private void handleCollectionComponentType(ComponentType componentType, String property,
            String collectionProperty, String entityName) {
        for (int i = 0; i < componentType.getSubtypes().length; i++) {
            Type subtype = componentType.getSubtypes()[i];

            String subProperty = property != null ? property + "." + componentType.getPropertyNames()[i]
                    : componentType.getPropertyNames()[i];

            if (subtype instanceof EntityType && RiotFile.class.isAssignableFrom(subtype.getReturnedClass())) {

                fileQueries.add(String.format(
                        "select file.id from %2$s ref "
                                + "join ref.%3$s as col join col.%1$s file where file is not null",
                        subProperty, entityName, collectionProperty));
            } else if (subtype.isComponentType()) {
                handleCollectionComponentType((ComponentType) subtype, subProperty, collectionProperty, entityName);
            }
        }
    }

}