/***************************************************************** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you 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.apache.cayenne.lifecycle.postcommit; import org.apache.cayenne.configuration.server.ServerModule; import org.apache.cayenne.di.Binder; import org.apache.cayenne.di.ListBuilder; import org.apache.cayenne.di.Module; import org.apache.cayenne.lifecycle.audit.Auditable; import org.apache.cayenne.lifecycle.postcommit.meta.AuditablePostCommitEntityFactory; import org.apache.cayenne.lifecycle.postcommit.meta.IncludeAllPostCommitEntityFactory; import org.apache.cayenne.lifecycle.postcommit.meta.PostCommitEntity; import org.apache.cayenne.lifecycle.postcommit.meta.PostCommitEntityFactory; import org.apache.cayenne.tx.TransactionFilter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.Collection; import java.util.HashSet; /** * A builder of a module that integrates {@link PostCommitFilter} and * {@link PostCommitListener} in Cayenne. * * @since 4.0 */ public class PostCommitModuleBuilder { private static final Logger LOGGER = LoggerFactory.getLogger(PostCommitModuleBuilder.class); public static PostCommitModuleBuilder builder() { return new PostCommitModuleBuilder(); } private Class<? extends PostCommitEntityFactory> entityFactoryType; private Collection<Class<? extends PostCommitListener>> listenerTypes; private Collection<PostCommitListener> listenerInstances; private boolean excludeFromTransaction; PostCommitModuleBuilder() { entityFactory(IncludeAllPostCommitEntityFactory.class); this.listenerTypes = new HashSet<>(); this.listenerInstances = new HashSet<>(); } public PostCommitModuleBuilder listener(Class<? extends PostCommitListener> type) { this.listenerTypes.add(type); return this; } public PostCommitModuleBuilder listener(PostCommitListener instance) { this.listenerInstances.add(instance); return this; } /** * If called, events will be dispatched outside of the main commit * transaction. By default events are dispatched within the transaction, so * listeners can commit their code together with the main commit. */ public PostCommitModuleBuilder excludeFromTransaction() { this.excludeFromTransaction = true; return this; } /** * Installs entity filter that would only include entities annotated with * {@link Auditable} on the callbacks. Also {@link Auditable#confidential()} * properties will be obfuscated and {@link Auditable#ignoredProperties()} - * excluded from the change collection. */ public PostCommitModuleBuilder auditableEntitiesOnly() { return entityFactory(AuditablePostCommitEntityFactory.class); } /** * Installs a custom factory for {@link PostCommitEntity} objects that * allows implementors to use their own annotations, etc. */ public PostCommitModuleBuilder entityFactory(Class<? extends PostCommitEntityFactory> entityFactoryType) { this.entityFactoryType = entityFactoryType; return this; } /** * Creates a DI module that would install {@link PostCommitFilter} and its * listeners in Cayenne. */ public Module build() { return new Module() { @SuppressWarnings({ "rawtypes", "unchecked" }) @Override public void configure(Binder binder) { if (listenerTypes.isEmpty() && listenerInstances.isEmpty()) { LOGGER.info("No listeners configured. Skipping PostCommitFilter registration"); return; } binder.bind(PostCommitEntityFactory.class).to(entityFactoryType); ListBuilder<PostCommitListener> listeners = PostCommitModule.contributeListeners(binder) .addAll(listenerInstances); // types have to be added one-by-one for (Class type : listenerTypes) { // TODO: temp hack - need to bind each type before adding to collection... binder.bind(type).to(type); listeners.add(type); } if (excludeFromTransaction) { ServerModule.contributeDomainFilters(binder).addAfter(PostCommitFilter.class, TransactionFilter.class); } else { ServerModule.contributeDomainFilters(binder).insertBefore(PostCommitFilter.class, TransactionFilter.class); } } }; } }