/* 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.components.index; import static org.hibernate.EntityMode.POJO; import java.util.Map; import org.hibernate.Hibernate; import org.hibernate.annotations.Filter; import org.hibernate.metadata.ClassMetadata; import org.riotfamily.common.util.Generics; import org.riotfamily.components.model.Content; import org.riotfamily.components.model.ContentContainer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.orm.hibernate3.support.HibernateDaoSupport; import org.springframework.util.Assert; import org.springframework.util.StringUtils; /** * ContentIndexer that allows the lookup of ContentContainerOwners. * <p> * If a Content has a ContainerContainerOwner of the type <code>Foo</code>, * the indexer will look for a mapped class called <code>FooContentIndex</code>, * that is a subclass of {@link ContentIndex}. * </p> * @see ContentIndex */ public class HibernateContentIndexer extends HibernateDaoSupport implements ContentIndexer { private Logger log = LoggerFactory.getLogger(HibernateContentIndexer.class); private Map<String, ClassMetadata> metaDataMap = Generics.newHashMap(); public void contentCreated(Content content) { Object index = createIndex(content); if (index != null) { getSession().save(index); } } public void contentDeleted(Content content) { Object index = loadIndexByContent(content); if (index != null) { getSession().delete(index); } } public void contentModified(Content content) { contentDeleted(content); contentCreated(content); } private Object createIndex(Content content) { ContentContainer container = content.getContainer(); if (container != null) { Object owner = container.getOwner(); if (owner != null) { String ownerClassName = Hibernate.getClass(owner).getName(); ClassMetadata meta = getIndexClassMetadata(ownerClassName); if (meta != null) { ContentIndex index = (ContentIndex) meta.instantiate(content.getId(), POJO); String ownerProperty = StringUtils.uncapitalize(StringUtils.unqualify(ownerClassName)); meta.setPropertyValue(index, ownerProperty, owner, POJO); index.setContent(content); return index; } } } return null; } private ClassMetadata getIndexClassMetadata(String ownerClassName) { if (metaDataMap.containsKey(ownerClassName)) { return metaDataMap.get(ownerClassName); } String indexClassName = ownerClassName + "ContentIndex"; ClassMetadata meta = getSessionFactory().getClassMetadata(indexClassName); if (meta != null) { Class<?> indexClass = meta.getMappedClass(POJO); if (ContentIndex.class.isAssignableFrom(indexClass)) { Filter filter = indexClass.getAnnotation(Filter.class); Assert.isTrue(filter != null && filter.name().equals("contentIndex"), String.format("%s must be annotated with @Filter(name=\"contentIndex\")", indexClass.getName())); } else { meta = null; log.warn("Class {} matches the naming convention for content " + "indexes but does not extend ContentIndex.", indexClass); } } metaDataMap.put(ownerClassName, meta); return meta; } private Object loadIndexByContent(Content content) { ContentContainer container = content.getContainer(); if (container != null) { Object owner = container.getOwner(); if (owner != null) { String ownerClassName = Hibernate.getClass(owner).getName(); ClassMetadata meta = getIndexClassMetadata(ownerClassName); if (meta != null) { return getSession().get(meta.getEntityName(), content.getId()); } } } return null; } }