[hibernate-commits] Hibernate SVN: r20181 - in search/trunk/hibernate-search/src: main/java/org/hibernate/search/engine and 3 other directories.
hibernate-commits at lists.jboss.org
hibernate-commits at lists.jboss.org
Thu Aug 19 07:52:38 EDT 2010
Author: hardy.ferentschik
Date: 2010-08-19 07:52:37 -0400 (Thu, 19 Aug 2010)
New Revision: 20181
Added:
search/trunk/hibernate-search/src/main/java/org/hibernate/search/jmx/JMXRegistrar.java
Modified:
search/trunk/hibernate-search/src/main/java/org/hibernate/search/batchindexing/BatchCoordinator.java
search/trunk/hibernate-search/src/main/java/org/hibernate/search/batchindexing/MassIndexerProgressMonitor.java
search/trunk/hibernate-search/src/main/java/org/hibernate/search/engine/SearchFactoryImplementor.java
search/trunk/hibernate-search/src/main/java/org/hibernate/search/impl/ImmutableSearchFactory.java
search/trunk/hibernate-search/src/main/java/org/hibernate/search/impl/MassIndexerImpl.java
search/trunk/hibernate-search/src/main/java/org/hibernate/search/impl/MutableSearchFactory.java
search/trunk/hibernate-search/src/main/java/org/hibernate/search/impl/SearchFactoryBuilder.java
search/trunk/hibernate-search/src/main/java/org/hibernate/search/impl/SimpleIndexingProgressMonitor.java
search/trunk/hibernate-search/src/main/java/org/hibernate/search/jmx/IndexingProgressMonitor.java
search/trunk/hibernate-search/src/test/java/org/hibernate/search/test/batchindexing/IndexingGeneratedCorpusTest.java
Log:
HSEARCH-278 Moved the bean un- and registering back into JMXRegistrar. Only kept SearchFactoryImplementor.isJMXEnabled. Added a indexCompleted life cycle method to MassIndexerProgressMonitor.
Modified: search/trunk/hibernate-search/src/main/java/org/hibernate/search/batchindexing/BatchCoordinator.java
===================================================================
--- search/trunk/hibernate-search/src/main/java/org/hibernate/search/batchindexing/BatchCoordinator.java 2010-08-19 11:51:16 UTC (rev 20180)
+++ search/trunk/hibernate-search/src/main/java/org/hibernate/search/batchindexing/BatchCoordinator.java 2010-08-19 11:52:37 UTC (rev 20181)
@@ -103,6 +103,7 @@
}
finally {
backend.close();
+ monitor.indexingCompleted();
}
}
Modified: search/trunk/hibernate-search/src/main/java/org/hibernate/search/batchindexing/MassIndexerProgressMonitor.java
===================================================================
--- search/trunk/hibernate-search/src/main/java/org/hibernate/search/batchindexing/MassIndexerProgressMonitor.java 2010-08-19 11:51:16 UTC (rev 20180)
+++ search/trunk/hibernate-search/src/main/java/org/hibernate/search/batchindexing/MassIndexerProgressMonitor.java 2010-08-19 11:52:37 UTC (rev 20181)
@@ -78,4 +78,9 @@
* ber added to total count
*/
void addToTotalCount(long count);
+
+ /**
+ * Called when the indexing is completed.
+ */
+ void indexingCompleted();
}
Modified: search/trunk/hibernate-search/src/main/java/org/hibernate/search/engine/SearchFactoryImplementor.java
===================================================================
--- search/trunk/hibernate-search/src/main/java/org/hibernate/search/engine/SearchFactoryImplementor.java 2010-08-19 11:51:16 UTC (rev 20180)
+++ search/trunk/hibernate-search/src/main/java/org/hibernate/search/engine/SearchFactoryImplementor.java 2010-08-19 11:52:37 UTC (rev 20181)
@@ -84,10 +84,6 @@
ErrorHandler getErrorHandler();
- ObjectName registerMBean(Object bean, String name, boolean allowMultipleObjects);
-
- void unRegisterMBean(ObjectName name);
-
boolean isJMXEnabled();
/**
Modified: search/trunk/hibernate-search/src/main/java/org/hibernate/search/impl/ImmutableSearchFactory.java
===================================================================
--- search/trunk/hibernate-search/src/main/java/org/hibernate/search/impl/ImmutableSearchFactory.java 2010-08-19 11:51:16 UTC (rev 20180)
+++ search/trunk/hibernate-search/src/main/java/org/hibernate/search/impl/ImmutableSearchFactory.java 2010-08-19 11:52:37 UTC (rev 20181)
@@ -23,7 +23,6 @@
*/
package org.hibernate.search.impl;
-import java.lang.management.ManagementFactory;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -32,9 +31,6 @@
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.ReentrantLock;
-import javax.management.MBeanServer;
-import javax.management.MalformedObjectNameException;
-import javax.management.ObjectName;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.search.Similarity;
@@ -59,6 +55,7 @@
import org.hibernate.search.engine.SearchFactoryImplementor;
import org.hibernate.search.exception.ErrorHandler;
import org.hibernate.search.filter.FilterCachingStrategy;
+import org.hibernate.search.jmx.JMXRegistrar;
import org.hibernate.search.jmx.StatisticsInfo;
import org.hibernate.search.jmx.StatisticsInfoMBean;
import org.hibernate.search.query.dsl.v2.QueryContextBuilder;
@@ -136,7 +133,9 @@
}
if ( isJMXEnabled() ) {
- registerMBean( new StatisticsInfo( statistics ), StatisticsInfoMBean.STATISTICS_MBEAN_OBJECT_NAME, false );
+ JMXRegistrar.registerMBean(
+ new StatisticsInfo( statistics ), StatisticsInfoMBean.STATISTICS_MBEAN_OBJECT_NAME
+ );
}
}
@@ -357,54 +356,6 @@
return errorHandler;
}
- public ObjectName registerMBean(Object bean, String name, boolean allowMultipleObjects) {
- if ( !isJMXEnabled() ) {
- return null;
- }
-
- ObjectName objectName = createObjectName( name );
- MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
- if ( mbs.isRegistered( objectName ) ) {
- try {
- mbs.unregisterMBean( objectName );
- }
- catch ( Exception e ) {
- log.warn( "Unable to un-register existing MBean: " + name, e );
- }
- }
-
- try {
- mbs.registerMBean( bean, objectName );
- }
- catch ( Exception e ) {
- throw new SearchException( "Unable to enable MBean for Hibernate Search", e );
- }
- return objectName;
- }
-
- public void unRegisterMBean(ObjectName name) {
- MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
- if ( mbs.isRegistered( name ) ) {
- try {
- mbs.unregisterMBean( name );
- }
- catch ( Exception e ) {
- log.warn( "Unable to un-register existing MBean: " + name, e );
- }
- }
- }
-
- private static ObjectName createObjectName(String name) {
- ObjectName objectName;
- try {
- objectName = new ObjectName( name );
- }
- catch ( MalformedObjectNameException e ) {
- throw new SearchException( "Invalid JMX Bean name: " + name, e );
- }
- return objectName;
- }
-
public PolymorphicIndexHierarchy getIndexHierarchy() {
return indexHierarchy;
}
Modified: search/trunk/hibernate-search/src/main/java/org/hibernate/search/impl/MassIndexerImpl.java
===================================================================
--- search/trunk/hibernate-search/src/main/java/org/hibernate/search/impl/MassIndexerImpl.java 2010-08-19 11:51:16 UTC (rev 20180)
+++ search/trunk/hibernate-search/src/main/java/org/hibernate/search/impl/MassIndexerImpl.java 2010-08-19 11:52:37 UTC (rev 20181)
@@ -76,11 +76,7 @@
this.sessionFactory = sessionFactory;
rootEntities = toRootEntities( searchFactoryImplementor, entities );
if ( searchFactoryImplementor.isJMXEnabled() ) {
- ObjectName name = searchFactoryImplementor.registerMBean(
- new IndexingProgressMonitor(),
- IndexingProgressMonitorMBean.INDEXING_PROGRESS_MONITOR_MBEAN_OBJECT_NAME,
- true
- );
+ monitor = new IndexingProgressMonitor();
}
}
Modified: search/trunk/hibernate-search/src/main/java/org/hibernate/search/impl/MutableSearchFactory.java
===================================================================
--- search/trunk/hibernate-search/src/main/java/org/hibernate/search/impl/MutableSearchFactory.java 2010-08-19 11:51:16 UTC (rev 20180)
+++ search/trunk/hibernate-search/src/main/java/org/hibernate/search/impl/MutableSearchFactory.java 2010-08-19 11:52:37 UTC (rev 20181)
@@ -170,14 +170,6 @@
return delegate.getErrorHandler();
}
- public ObjectName registerMBean(Object bean, String name, boolean allowMultipleObjects) {
- return delegate.registerMBean( bean, name, allowMultipleObjects );
- }
-
- public void unRegisterMBean(ObjectName name) {
- delegate.unRegisterMBean( name );
- }
-
public boolean isJMXEnabled() {
return delegate.isJMXEnabled();
}
Modified: search/trunk/hibernate-search/src/main/java/org/hibernate/search/impl/SearchFactoryBuilder.java
===================================================================
--- search/trunk/hibernate-search/src/main/java/org/hibernate/search/impl/SearchFactoryBuilder.java 2010-08-19 11:51:16 UTC (rev 20180)
+++ search/trunk/hibernate-search/src/main/java/org/hibernate/search/impl/SearchFactoryBuilder.java 2010-08-19 11:52:37 UTC (rev 20181)
@@ -75,6 +75,7 @@
import org.hibernate.search.filter.MRUFilterCachingStrategy;
import org.hibernate.search.filter.ShardSensitiveOnlyFilter;
import org.hibernate.search.jmx.IndexCtrl;
+import org.hibernate.search.jmx.JMXRegistrar;
import org.hibernate.search.reader.ReaderProvider;
import org.hibernate.search.reader.ReaderProviderFactory;
import org.hibernate.search.spi.WorkerBuildContext;
@@ -168,7 +169,7 @@
// if we have a JNDI bound SessionFactory we can also enable the index control bean
if ( StringHelper.isNotEmpty( configurationProperties.getProperty( "hibernate.session_factory_name" ) ) ) {
IndexCtrl indexCtrlBean = new IndexCtrl( configurationProperties );
- searchFactoryImplementor.registerMBean( indexCtrlBean, IndexCtrl.INDEX_CTRL_MBEAN_OBJECT_NAME, false );
+ JMXRegistrar.registerMBean( indexCtrlBean, IndexCtrl.INDEX_CTRL_MBEAN_OBJECT_NAME );
}
}
Modified: search/trunk/hibernate-search/src/main/java/org/hibernate/search/impl/SimpleIndexingProgressMonitor.java
===================================================================
--- search/trunk/hibernate-search/src/main/java/org/hibernate/search/impl/SimpleIndexingProgressMonitor.java 2010-08-19 11:51:16 UTC (rev 20180)
+++ search/trunk/hibernate-search/src/main/java/org/hibernate/search/impl/SimpleIndexingProgressMonitor.java 2010-08-19 11:52:37 UTC (rev 20181)
@@ -1,26 +1,25 @@
-/* $Id$
- *
+/*
* Hibernate, Relational Persistence for Idiomatic Java
- *
- * Copyright (c) 2009, Red Hat, Inc. and/or its affiliates or third-party contributors as
- * indicated by the @author tags or express copyright attribution
- * statements applied by the authors. All third-party contributions are
- * distributed under license by Red Hat, Inc.
- *
- * This copyrighted material is made available to anyone wishing to use, modify,
- * copy, or redistribute it subject to the terms and conditions of the GNU
- * Lesser General Public License, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
- * for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this distribution; if not, write to:
- * Free Software Foundation, Inc.
- * 51 Franklin Street, Fifth Floor
- * Boston, MA 02110-1301 USA
+ *
+ * Copyright (c) 2010, Red Hat, Inc. and/or its affiliates or third-party contributors as
+ * indicated by the @author tags or express copyright attribution
+ * statements applied by the authors. All third-party contributions are
+ * distributed under license by Red Hat, Inc.
+ *
+ * This copyrighted material is made available to anyone wishing to use, modify,
+ * copy, or redistribute it subject to the terms and conditions of the GNU
+ * Lesser General Public License, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this distribution; if not, write to:
+ * Free Software Foundation, Inc.
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02110-1301 USA
*/
package org.hibernate.search.impl;
@@ -32,7 +31,7 @@
import org.hibernate.search.util.LoggerFactory;
/**
- * A very simple implementation of {@code MassIndexerProgressMonitor}
+ * A very simple implementation of {@code MassIndexerProgressMonitor}.
*
* @author Sanne Grinovero
*/
@@ -66,6 +65,10 @@
log.info( "Going to reindex {} entities", count );
}
+ public void indexingCompleted() {
+ log.info( "Reindexed {} entities", totalCounter.get() );
+ }
+
protected int getStatusMessagePeriod() {
return 50;
}
Modified: search/trunk/hibernate-search/src/main/java/org/hibernate/search/jmx/IndexingProgressMonitor.java
===================================================================
--- search/trunk/hibernate-search/src/main/java/org/hibernate/search/jmx/IndexingProgressMonitor.java 2010-08-19 11:51:16 UTC (rev 20180)
+++ search/trunk/hibernate-search/src/main/java/org/hibernate/search/jmx/IndexingProgressMonitor.java 2010-08-19 11:52:37 UTC (rev 20181)
@@ -24,8 +24,12 @@
package org.hibernate.search.jmx;
import java.util.concurrent.atomic.AtomicLong;
+import javax.management.ObjectName;
+import org.slf4j.Logger;
+
import org.hibernate.search.batchindexing.MassIndexerProgressMonitor;
+import org.hibernate.search.util.LoggerFactory;
/**
* A JMX based mass indexer progress monitor. This monitor will allow you to follow mass indexing progress via JMX.
@@ -33,12 +37,23 @@
* @author Hardy Ferentschik
*/
public class IndexingProgressMonitor implements IndexingProgressMonitorMBean, MassIndexerProgressMonitor {
+ private static final Logger log = LoggerFactory.make();
private final AtomicLong documentsDoneCounter = new AtomicLong();
private final AtomicLong documentsBuiltCounter = new AtomicLong();
private final AtomicLong totalCounter = new AtomicLong();
private final AtomicLong entitiesLoadedCounter = new AtomicLong();
+ private final ObjectName registeredName;
+
+ public IndexingProgressMonitor() {
+ String name = IndexingProgressMonitorMBean.INDEXING_PROGRESS_MONITOR_MBEAN_OBJECT_NAME;
+ if ( JMXRegistrar.isNameRegistered( name ) ) {
+ name = name + "@" + Integer.toHexString( hashCode() ); // make the name unique in case there are multiple mass indexers at the same time
+ }
+ registeredName = JMXRegistrar.registerMBean( this, name );
+ }
+
public void documentsAdded(long increment) {
documentsDoneCounter.addAndGet( increment );
}
@@ -55,6 +70,11 @@
totalCounter.addAndGet( count );
}
+ public void indexingCompleted() {
+ log.info( "Indexing completed. Reindexed {} entities. Unregistering MBean from server", totalCounter.get() );
+ JMXRegistrar.unRegisterMBean( registeredName );
+ }
+
public long getLoadedEntitiesCount() {
return entitiesLoadedCounter.get();
}
Added: search/trunk/hibernate-search/src/main/java/org/hibernate/search/jmx/JMXRegistrar.java
===================================================================
--- search/trunk/hibernate-search/src/main/java/org/hibernate/search/jmx/JMXRegistrar.java (rev 0)
+++ search/trunk/hibernate-search/src/main/java/org/hibernate/search/jmx/JMXRegistrar.java 2010-08-19 11:52:37 UTC (rev 20181)
@@ -0,0 +1,117 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2010, Red Hat, Inc. and/or its affiliates or third-party contributors as
+ * indicated by the @author tags or express copyright attribution
+ * statements applied by the authors. All third-party contributions are
+ * distributed under license by Red Hat, Inc.
+ *
+ * This copyrighted material is made available to anyone wishing to use, modify,
+ * copy, or redistribute it subject to the terms and conditions of the GNU
+ * Lesser General Public License, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this distribution; if not, write to:
+ * Free Software Foundation, Inc.
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02110-1301 USA
+ */
+package org.hibernate.search.jmx;
+
+import java.lang.management.ManagementFactory;
+import javax.management.MBeanServer;
+import javax.management.MalformedObjectNameException;
+import javax.management.ObjectName;
+
+import org.slf4j.Logger;
+
+import org.hibernate.search.SearchException;
+import org.hibernate.search.util.LoggerFactory;
+
+/**
+ * Helper class to register JMX beans.
+ *
+ * @author Hardy Ferentschik
+ */
+public final class JMXRegistrar {
+ private static final Logger log = LoggerFactory.make();
+
+ private JMXRegistrar() {
+ }
+
+ /**
+ * Registers the specified object with the given name to the MBean server.
+ *
+ * @param object the object to register
+ * @param name the object name to register the bean under
+ *
+ * @return The registered object name
+ */
+ public static ObjectName registerMBean(Object object, String name) {
+ ObjectName objectName = createObjectName( name );
+ MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
+ try {
+ mbs.registerMBean( object, objectName );
+ }
+ catch ( Exception e ) {
+ throw new SearchException( "Unable to enable MBean for Hibernate Search", e );
+ }
+ return objectName;
+ }
+
+ /**
+ * Unregister the MBean with the specified name.
+ *
+ * @param name The object name of the bean to unregister. The {@code name} cannot be {@code null}
+ *
+ * @throws IllegalArgumentException In case the object name is {@code null}
+ */
+ public static void unRegisterMBean(ObjectName name) {
+ if ( name == null ) {
+ throw new IllegalArgumentException( "The object name cannot be null" );
+ }
+ MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
+ if ( mbs.isRegistered( name ) ) {
+ try {
+ mbs.unregisterMBean( name );
+ }
+ catch ( Exception e ) {
+ log.warn( "Unable to un-register existing MBean: " + name, e );
+ }
+ }
+ }
+
+ /**
+ * Checks whether a bean is registered under the given name.
+ *
+ * @param name the object name to check (as string)
+ * @return {@code true} is there is a bean registered under the given name, {@code false} otherwise.
+ * @throws IllegalArgumentException In case the object name is {@code null}
+ */
+ public static boolean isNameRegistered(String name) {
+ if ( name == null ) {
+ throw new IllegalArgumentException( "The object name cannot be null" );
+ }
+ ObjectName objectName = createObjectName( name );
+ MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
+ return mbs.isRegistered( objectName );
+ }
+
+ private static ObjectName createObjectName(String name) {
+ ObjectName objectName;
+ try {
+ objectName = new ObjectName( name );
+ }
+ catch ( MalformedObjectNameException e ) {
+ throw new SearchException( "Invalid JMX Bean name: " + name, e );
+ }
+ return objectName;
+ }
+}
+
+
Modified: search/trunk/hibernate-search/src/test/java/org/hibernate/search/test/batchindexing/IndexingGeneratedCorpusTest.java
===================================================================
--- search/trunk/hibernate-search/src/test/java/org/hibernate/search/test/batchindexing/IndexingGeneratedCorpusTest.java 2010-08-19 11:51:16 UTC (rev 20180)
+++ search/trunk/hibernate-search/src/test/java/org/hibernate/search/test/batchindexing/IndexingGeneratedCorpusTest.java 2010-08-19 11:52:37 UTC (rev 20181)
@@ -1,26 +1,25 @@
-/* $Id$
- *
+/*
* Hibernate, Relational Persistence for Idiomatic Java
- *
- * Copyright (c) 2009, Red Hat, Inc. and/or its affiliates or third-party contributors as
- * indicated by the @author tags or express copyright attribution
- * statements applied by the authors. All third-party contributions are
- * distributed under license by Red Hat, Inc.
- *
- * This copyrighted material is made available to anyone wishing to use, modify,
- * copy, or redistribute it subject to the terms and conditions of the GNU
- * Lesser General Public License, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
- * for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this distribution; if not, write to:
- * Free Software Foundation, Inc.
- * 51 Franklin Street, Fifth Floor
- * Boston, MA 02110-1301 USA
+ *
+ * Copyright (c) 2010, Red Hat, Inc. and/or its affiliates or third-party contributors as
+ * indicated by the @author tags or express copyright attribution
+ * statements applied by the authors. All third-party contributions are
+ * distributed under license by Red Hat, Inc.
+ *
+ * This copyrighted material is made available to anyone wishing to use, modify,
+ * copy, or redistribute it subject to the terms and conditions of the GNU
+ * Lesser General Public License, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this distribution; if not, write to:
+ * Free Software Foundation, Inc.
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02110-1301 USA
*/
package org.hibernate.search.test.batchindexing;
@@ -31,7 +30,6 @@
import org.apache.lucene.search.Query;
import org.hibernate.Transaction;
-import org.hibernate.search.Environment;
import org.hibernate.search.FullTextQuery;
import org.hibernate.search.FullTextSession;
import org.hibernate.search.backend.impl.batchlucene.LuceneBatchBackend;
@@ -63,14 +61,8 @@
.addAnnotatedClass( Dvd.class )
.addAnnotatedClass( AncientBook.class )
.addAnnotatedClass( Nation.class )
- .setProperty( "hibernate.show_sql", "false" ) //too verbose for this test
+ .setProperty( "hibernate.show_sql", "false" ) // too verbose for this test
.setProperty( LuceneBatchBackend.CONCURRENT_WRITERS, "4" )
- .setProperty( "hibernate.session_factory_name", "java:comp/SessionFactory" )
- .setProperty( "hibernate.jndi.class", "org.osjava.sj.SimpleContextFactory" )
- .setProperty( "hibernate.jndi.org.osjava.sj.root", "/Users/hardy/tmp/jndi-entries" )
- .setProperty( "hibernate.jndi.org.osjava.sj.jndi.shared", "true" )
- .setProperty( Environment.JMX_ENABLED, "true" )
- .setProperty( Environment.GENERATE_STATS, "true" )
.build();
createMany( Book.class, BOOK_NUM );
createMany( Dvd.class, DVD_NUM );
More information about the hibernate-commits
mailing list