Java tutorial
/* 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); } } } }