Author: hardy.ferentschik
Date: 2010-07-05 10:46:01 -0400 (Mon, 05 Jul 2010)
New Revision: 19897
Added:
search/trunk/hibernate-search/src/main/java/org/hibernate/search/jmx/
search/trunk/hibernate-search/src/main/java/org/hibernate/search/jmx/HibernateSearchConfigInfo.java
search/trunk/hibernate-search/src/main/java/org/hibernate/search/jmx/HibernateSearchConfigInfoMBean.java
search/trunk/hibernate-search/src/main/java/org/hibernate/search/jmx/HibernateSearchIndexCtrl.java
search/trunk/hibernate-search/src/main/java/org/hibernate/search/jmx/HibernateSearchIndexCtrlMBean.java
search/trunk/hibernate-search/src/main/java/org/hibernate/search/util/JNDIHelper.java
search/trunk/hibernate-search/src/test/java/org/hibernate/search/test/jmx/
search/trunk/hibernate-search/src/test/java/org/hibernate/search/test/jmx/ConfigInfoMBeanTest.java
search/trunk/hibernate-search/src/test/java/org/hibernate/search/test/jmx/Counter.java
search/trunk/hibernate-search/src/test/java/org/hibernate/search/test/jmx/IndexCtrlMBeanTest.java
search/trunk/hibernate-search/src/test/java/org/hibernate/search/test/jmx/NoMBeansEnabledTest.java
Removed:
search/trunk/hibernate-search/src/test/resources/jndi.properties
Modified:
search/trunk/hibernate-search-testing/src/main/java/org/hibernate/search/test/SearchTestCase.java
search/trunk/hibernate-search/pom.xml
search/trunk/hibernate-search/src/main/java/org/hibernate/search/Environment.java
search/trunk/hibernate-search/src/main/java/org/hibernate/search/Search.java
search/trunk/hibernate-search/src/main/java/org/hibernate/search/backend/LuceneIndexingParameters.java
search/trunk/hibernate-search/src/main/java/org/hibernate/search/backend/impl/jms/JMSBackendQueueProcessorFactory.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/SearchFactoryBuilder.java
search/trunk/hibernate-search/src/test/java/org/hibernate/search/test/SearchTestCase.java
search/trunk/hibernate-search/src/test/java/org/hibernate/search/test/jms/master/JMSMasterTest.java
search/trunk/hibernate-search/src/test/java/org/hibernate/search/test/jms/slave/JMSSlaveTest.java
Log:
HSEARCH-278 (Create a Search Statistic JMX Bean)
* Added two MBeans - HibernateSearchConfigInfoMBean and HibernateSearchIndexCtrlMBean -
with their implementing classes and tests
* Introduced simple-jndi as new dependecy for testing of MBean functionaly
* Refactored all JNDI based tests to not rely on jndi.properties, but rather pass jndi
related setting as config parameters
* Some minor formatting
Modified: search/trunk/hibernate-search/pom.xml
===================================================================
--- search/trunk/hibernate-search/pom.xml 2010-07-05 14:30:38 UTC (rev 19896)
+++ search/trunk/hibernate-search/pom.xml 2010-07-05 14:46:01 UTC (rev 19897)
@@ -22,7 +22,9 @@
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
-->
-<project
xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/maven-v4_0_0.xsd">
+<project
xmlns="http://maven.apache.org/POM/4.0.0"
+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
@@ -76,11 +78,11 @@
<artifactId>jms</artifactId>
<scope>provided</scope>
</dependency>
- <dependency>
- <groupId>javax.annotation</groupId>
- <artifactId>jsr250-api</artifactId>
+ <dependency>
+ <groupId>javax.annotation</groupId>
+ <artifactId>jsr250-api</artifactId>
<scope>provided</scope>
- </dependency>
+ </dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
@@ -96,6 +98,12 @@
<artifactId>activemq-core</artifactId>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>simple-jndi</groupId>
+ <artifactId>simple-jndi</artifactId>
+ <version>0.11.4</version>
+ <scope>test</scope>
+ </dependency>
</dependencies>
<build>
@@ -139,6 +147,10 @@
<name>java.net.preferIPv4Stack</name>
<value>true</value>
</property>
+ <property>
+ <name>com.sun.management.jmxremote</name>
+ <value>true</value>
+ </property>
</systemProperties>
<excludes>
<exclude>**/classloading/*.java</exclude>
@@ -187,7 +199,10 @@
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-release-plugin</artifactId>
<configuration>
- <goals>deploy javadoc:javadoc
org.jboss.maven.plugins:maven-jdocbook-plugin:2.2.3:translate
org.jboss.maven.plugins:maven-jdocbook-plugin:2.2.3:resources
org.jboss.maven.plugins:maven-jdocbook-plugin:2.2.3:generate
assembly:assembly</goals>
+ <goals>deploy javadoc:javadoc
org.jboss.maven.plugins:maven-jdocbook-plugin:2.2.3:translate
+ org.jboss.maven.plugins:maven-jdocbook-plugin:2.2.3:resources
+ org.jboss.maven.plugins:maven-jdocbook-plugin:2.2.3:generate
assembly:assembly
+ </goals>
</configuration>
</plugin>
<plugin>
Modified:
search/trunk/hibernate-search/src/main/java/org/hibernate/search/Environment.java
===================================================================
---
search/trunk/hibernate-search/src/main/java/org/hibernate/search/Environment.java 2010-07-05
14:30:38 UTC (rev 19896)
+++
search/trunk/hibernate-search/src/main/java/org/hibernate/search/Environment.java 2010-07-05
14:46:01 UTC (rev 19897)
@@ -66,12 +66,12 @@
* default 1
*/
public static final String WORKER_THREADPOOL_SIZE = Environment.WORKER_PREFIX +
"thread_pool.size";
-
+
/**
* Size of the buffer queue (besides the thread pool size)
* <ul>
- * <li>only used then execution is async</li>
- * <li>default infinite</li>
+ * <li>only used then execution is async</li>
+ * <li>default infinite</li>
* </ul>
*/
public static final String WORKER_WORKQUEUE_SIZE = Environment.WORKER_PREFIX +
"buffer_queue.max";
@@ -80,28 +80,28 @@
* define the reader prefix
*/
public static final String READER_PREFIX = "hibernate.search.reader.";
-
+
/**
* define the reader strategy used
*/
public static final String READER_STRATEGY = READER_PREFIX + "strategy";
-
+
/**
* filter caching strategy class (must have a no-arg constructor and implement
FilterCachingStrategy)
*/
public static final String FILTER_CACHING_STRATEGY =
"hibernate.search.filter.cache_strategy";
-
+
/**
* number of docidresults cached in hard reference.
*/
public static final String CACHE_DOCIDRESULTS_SIZE =
"hibernate.search.filter.cache_docidresults.size";
-
+
/**
* batch backend implementation class (must have a no-arg constructor and implement
BatchBackend)
* also prefix for configuration settings of the batch backend
*/
public static final String BATCH_BACKEND = "hibernate.search.batchbackend";
-
+
/**
* When set to true a lock on the index will not be released until the
* SearchFactory (or SessionFactory) is closed.
@@ -111,17 +111,19 @@
*/
public static final String EXCLUSIVE_INDEX_USE = "exclusive_index_use";
- /**
- *
- */
public static final String MODEL_MAPPING = "hibernate.search.model_mapping";
-
/**
* Set to a fully qualified classname of a type implementing
org.hibernate.search.exception.ErrorHandler
* to override the error strategy used during processing of the Lucene updates.
* Default is to log errors.
*/
public static final String ERROR_HANDLER = "hibernate.search.error_handler";
-
+
+ /**
+ * If set to {@code true} the JMX Statistics bean gets enabled. For all other values the
bean does not
+ * get enabled.
+ */
+ public static final String JMX_ENABLED = "hibernate.search.jmx_enabled";
+
}
Modified: search/trunk/hibernate-search/src/main/java/org/hibernate/search/Search.java
===================================================================
---
search/trunk/hibernate-search/src/main/java/org/hibernate/search/Search.java 2010-07-05
14:30:38 UTC (rev 19896)
+++
search/trunk/hibernate-search/src/main/java/org/hibernate/search/Search.java 2010-07-05
14:46:01 UTC (rev 19897)
@@ -29,7 +29,7 @@
/**
* Helper class to get a FullTextSession out of a regular session.
- *
+ *
* @author Emmanuel Bernard
* @author Hardy Ferentschik
*/
@@ -39,19 +39,19 @@
}
public static FullTextSession getFullTextSession(Session session) {
- if (session instanceof FullTextSessionImpl) {
- return (FullTextSession) session;
+ if ( session instanceof FullTextSessionImpl ) {
+ return ( FullTextSession ) session;
}
else {
- return new FullTextSessionImpl(session);
+ return new FullTextSessionImpl( session );
}
}
-
+
/**
* @deprecated As of release 3.1.0, replaced by {@link #getFullTextSession(Session)}
*/
- @Deprecated
+ @Deprecated
public static FullTextSession createFullTextSession(Session session) {
- return getFullTextSession(session);
+ return getFullTextSession( session );
}
}
Modified:
search/trunk/hibernate-search/src/main/java/org/hibernate/search/backend/LuceneIndexingParameters.java
===================================================================
---
search/trunk/hibernate-search/src/main/java/org/hibernate/search/backend/LuceneIndexingParameters.java 2010-07-05
14:30:38 UTC (rev 19896)
+++
search/trunk/hibernate-search/src/main/java/org/hibernate/search/backend/LuceneIndexingParameters.java 2010-07-05
14:46:01 UTC (rev 19897)
@@ -107,6 +107,16 @@
return batchIndexParameters;
}
+ @Override
+ public String toString() {
+ final StringBuilder sb = new StringBuilder();
+ sb.append( "LuceneIndexingParameters" );
+ sb.append( "{batchIndexParameters=" ).append( batchIndexParameters );
+ sb.append( ", transactionIndexParameters=" ).append(
transactionIndexParameters );
+ sb.append( '}' );
+ return sb.toString();
+ }
+
public static class ParameterSet implements Serializable {
private static final long serialVersionUID = -6121723702279869524L;
@@ -182,9 +192,17 @@
return false;
return true;
}
-
- }
+ @Override
+ public String toString() {
+ final StringBuilder sb = new StringBuilder();
+ sb.append( "ParameterSet" );
+ sb.append( "{parameters=" ).append( parameters );
+ sb.append( '}' );
+ return sb.toString();
+ }
+ }
+
public void applyToWriter(IndexWriter writer, boolean batch) {
if ( batch ) {
getBatchIndexParameters().applyToWriter( writer );
Modified:
search/trunk/hibernate-search/src/main/java/org/hibernate/search/backend/impl/jms/JMSBackendQueueProcessorFactory.java
===================================================================
---
search/trunk/hibernate-search/src/main/java/org/hibernate/search/backend/impl/jms/JMSBackendQueueProcessorFactory.java 2010-07-05
14:30:38 UTC (rev 19896)
+++
search/trunk/hibernate-search/src/main/java/org/hibernate/search/backend/impl/jms/JMSBackendQueueProcessorFactory.java 2010-07-05
14:46:01 UTC (rev 19897)
@@ -1,8 +1,7 @@
-/* $Id$
- *
+/*
* Hibernate, Relational Persistence for Idiomatic Java
*
- * Copyright (c) 2009, Red Hat, Inc. and/or its affiliates or third-party contributors
as
+ * 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.
@@ -24,26 +23,25 @@
*/
package org.hibernate.search.backend.impl.jms;
-import java.util.HashSet;
-import java.util.Iterator;
import java.util.List;
import java.util.Properties;
import java.util.Set;
import javax.jms.Queue;
import javax.jms.QueueConnectionFactory;
-import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import org.hibernate.search.Environment;
-import org.hibernate.search.backend.UpdatableBackendQueueProcessorFactory;
-import org.hibernate.search.spi.WorkerBuildContext;
import org.hibernate.search.SearchException;
import org.hibernate.search.backend.LuceneWork;
+import org.hibernate.search.backend.UpdatableBackendQueueProcessorFactory;
+import org.hibernate.search.spi.WorkerBuildContext;
import org.hibernate.search.store.DirectoryProvider;
+import org.hibernate.search.util.JNDIHelper;
/**
* @author Emmanuel Bernard
+ * @author Hardy Ferentschik
*/
public class JMSBackendQueueProcessorFactory implements
UpdatableBackendQueueProcessorFactory {
private String jmsQueueName;
@@ -56,7 +54,7 @@
public static final String JMS_QUEUE = Environment.WORKER_PREFIX +
"jms.queue";
public void initialize(Properties props, WorkerBuildContext context) {
- //TODO proper exception if jms queues and connecitons are not there
+ //TODO proper exception if jms queues and connections are not there
this.properties = props;
this.jmsConnectionFactoryName = props.getProperty( JMS_CONNECTION_FACTORY );
this.jmsQueueName = props.getProperty( JMS_QUEUE );
@@ -86,67 +84,30 @@
}
public void prepareJMSTools() {
- if ( jmsQueue != null && factory != null ) return;
+ if ( jmsQueue != null && factory != null ) {
+ return;
+ }
try {
- InitialContext initialContext = getInitialContext( properties );
- factory = (QueueConnectionFactory) initialContext.lookup( jmsConnectionFactoryName );
- jmsQueue = (Queue) initialContext.lookup( jmsQueueName );
+ InitialContext initialContext = JNDIHelper.getInitialContext( properties, JNDI_PREFIX
);
+ factory = ( QueueConnectionFactory ) initialContext.lookup( jmsConnectionFactoryName
);
+ jmsQueue = ( Queue ) initialContext.lookup( jmsQueueName );
}
- catch (NamingException e) {
- throw new SearchException( "Unable to lookup Search queue ("
- + ( jmsQueueName != null ?
- jmsQueueName :
- "null" ) + ") and connection factory ("
- + ( jmsConnectionFactoryName != null ?
- jmsConnectionFactoryName :
- "null" ) + ")",
+ catch ( NamingException e ) {
+ throw new SearchException(
+ "Unable to lookup Search queue ("
+ + ( jmsQueueName != null ?
+ jmsQueueName :
+ "null" ) + ") and connection factory ("
+ + ( jmsConnectionFactoryName != null ?
+ jmsConnectionFactoryName :
+ "null" ) + ")",
e
);
}
}
- private InitialContext getInitialContext(Properties properties) throws NamingException
{
- Properties jndiProps = getJndiProperties( properties );
- if ( jndiProps.size() == 0 ) {
- return new InitialContext();
- }
- else {
- return new InitialContext( jndiProps );
- }
- }
-
- private static Properties getJndiProperties(Properties properties) {
-
- HashSet specialProps = new HashSet();
- specialProps.add( JNDI_PREFIX + "class" );
- specialProps.add( JNDI_PREFIX + "url" );
-
- Iterator iter = properties.keySet().iterator();
- Properties result = new Properties();
- while ( iter.hasNext() ) {
- String prop = (String) iter.next();
- if ( prop.indexOf( JNDI_PREFIX ) > -1 && !specialProps.contains( prop ) )
{
- result.setProperty(
- prop.substring( JNDI_PREFIX.length() ),
- properties.getProperty( prop )
- );
- }
- }
-
- String jndiClass = properties.getProperty( JNDI_PREFIX + "class" );
- String jndiURL = properties.getProperty( JNDI_PREFIX + "url" );
- // we want to be able to just use the defaults,
- // if JNDI environment properties are not supplied
- // so don't put null in anywhere
- if ( jndiClass != null ) result.put( Context.INITIAL_CONTEXT_FACTORY, jndiClass );
- if ( jndiURL != null ) result.put( Context.PROVIDER_URL, jndiURL );
-
- return result;
- }
-
public void close() {
// no need to release anything
}
-
}
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-07-05
14:30:38 UTC (rev 19896)
+++
search/trunk/hibernate-search/src/main/java/org/hibernate/search/impl/ImmutableSearchFactory.java 2010-07-05
14:46:01 UTC (rev 19897)
@@ -35,9 +35,6 @@
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.search.Similarity;
-import org.hibernate.search.spi.internals.DirectoryProviderData;
-import org.hibernate.search.spi.internals.PolymorphicIndexHierarchy;
-import org.hibernate.search.spi.internals.StateSearchFactoryImplementor;
import org.slf4j.Logger;
import org.hibernate.annotations.common.AssertionFailure;
@@ -63,6 +60,9 @@
import org.hibernate.search.query.dsl.v2.impl.ConnectedQueryContextBuilder;
import org.hibernate.search.reader.ReaderProvider;
import org.hibernate.search.spi.WorkerBuildContext;
+import org.hibernate.search.spi.internals.DirectoryProviderData;
+import org.hibernate.search.spi.internals.PolymorphicIndexHierarchy;
+import org.hibernate.search.spi.internals.StateSearchFactoryImplementor;
import org.hibernate.search.store.DirectoryProvider;
import org.hibernate.search.store.optimization.OptimizerStrategy;
import org.hibernate.search.util.LoggerFactory;
@@ -71,7 +71,7 @@
/**
* This implementation is never directly exposed to the user, it is always wrapped into a
{@link org.hibernate.search.impl.MutableSearchFactory}
- *
+ *
* @author Emmanuel Bernard
*/
public class ImmutableSearchFactory implements StateSearchFactoryImplementor,
WorkerBuildContext {
@@ -122,7 +122,6 @@
this.worker = cfg.worker;
}
-
public BackendQueueProcessorFactory getBackendQueueProcessorFactory() {
return backendQueueProcessorFactory;
}
@@ -202,7 +201,7 @@
}
public void setBackendQueueProcessorFactory(BackendQueueProcessorFactory
backendQueueProcessorFactory) {
- throw new AssertionFailure( "ImmutableSearchFactory is immutable: should never be
called");
+ throw new AssertionFailure( "ImmutableSearchFactory is immutable: should never be
called" );
}
public OptimizerStrategy getOptimizerStrategy(DirectoryProvider<?> provider) {
@@ -296,7 +295,7 @@
public Set<Class<?>> getIndexedTypesPolymorphic(Class<?>[] classes) {
return indexHierarchy.getIndexedClasses( classes );
}
-
+
public BatchBackend makeBatchBackend(MassIndexerProgressMonitor progressMonitor) {
BatchBackend batchBackend;
String impl = configurationProperties.getProperty( Environment.BATCH_BACKEND );
@@ -304,18 +303,23 @@
batchBackend = new LuceneBatchBackend();
}
else {
- batchBackend = PluginLoader.instanceFromName( BatchBackend.class, impl,
ImmutableSearchFactory.class,
- "batchbackend" );
+ batchBackend = PluginLoader.instanceFromName(
+ BatchBackend.class, impl, ImmutableSearchFactory.class,
+ "batchbackend"
+ );
}
Properties batchBackendConfiguration = new MaskedProperty(
- this.configurationProperties, Environment.BATCH_BACKEND );
+ this.configurationProperties, Environment.BATCH_BACKEND
+ );
batchBackend.initialize( batchBackendConfiguration, progressMonitor, this );
return batchBackend;
}
public Similarity getSimilarity(DirectoryProvider<?> provider) {
Similarity similarity = dirProviderData.get( provider ).getSimilarity();
- if ( similarity == null ) throw new SearchException( "Assertion error: a
similarity should be defined for each provider" );
+ if ( similarity == null ) {
+ throw new SearchException( "Assertion error: a similarity should be defined for
each provider" );
+ }
return similarity;
}
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-07-05
14:30:38 UTC (rev 19896)
+++
search/trunk/hibernate-search/src/main/java/org/hibernate/search/impl/SearchFactoryBuilder.java 2010-07-05
14:46:01 UTC (rev 19897)
@@ -1,6 +1,30 @@
+/*
+ * 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.impl;
import java.beans.Introspector;
+import java.lang.management.ManagementFactory;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
@@ -12,16 +36,12 @@
import java.util.Properties;
import java.util.Set;
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;
-
-import org.hibernate.search.backend.UpdatableBackendQueueProcessorFactory;
-import org.hibernate.search.spi.WorkerBuildContext;
-import org.hibernate.search.spi.WritableBuildContext;
-import org.hibernate.search.spi.internals.DirectoryProviderData;
-import org.hibernate.search.spi.internals.PolymorphicIndexHierarchy;
-import org.hibernate.search.spi.internals.StateSearchFactoryImplementor;
import org.slf4j.Logger;
import org.hibernate.annotations.common.reflection.MetadataProvider;
@@ -40,6 +60,7 @@
import org.hibernate.search.annotations.Key;
import org.hibernate.search.backend.BackendQueueProcessorFactory;
import org.hibernate.search.backend.LuceneIndexingParameters;
+import org.hibernate.search.backend.UpdatableBackendQueueProcessorFactory;
import org.hibernate.search.backend.Worker;
import org.hibernate.search.backend.WorkerFactory;
import org.hibernate.search.backend.configuration.ConfigurationParseHelper;
@@ -56,8 +77,16 @@
import org.hibernate.search.filter.FilterCachingStrategy;
import org.hibernate.search.filter.MRUFilterCachingStrategy;
import org.hibernate.search.filter.ShardSensitiveOnlyFilter;
+import org.hibernate.search.jmx.HibernateSearchConfigInfo;
+import org.hibernate.search.jmx.HibernateSearchConfigInfoMBean;
+import org.hibernate.search.jmx.HibernateSearchIndexCtrl;
import org.hibernate.search.reader.ReaderProvider;
import org.hibernate.search.reader.ReaderProviderFactory;
+import org.hibernate.search.spi.WorkerBuildContext;
+import org.hibernate.search.spi.WritableBuildContext;
+import org.hibernate.search.spi.internals.DirectoryProviderData;
+import org.hibernate.search.spi.internals.PolymorphicIndexHierarchy;
+import org.hibernate.search.spi.internals.StateSearchFactoryImplementor;
import org.hibernate.search.store.DirectoryProvider;
import org.hibernate.search.store.DirectoryProviderFactory;
import org.hibernate.search.store.optimization.OptimizerStrategy;
@@ -67,8 +96,10 @@
import org.hibernate.util.StringHelper;
/**
- * Build a search factory
+ * Build a search factory.
+ *
* @author Emmanuel Bernard
+ * @author Hardy Ferentschik
*/
public class SearchFactoryBuilder {
private static final Logger log = LoggerFactory.make();
@@ -111,25 +142,75 @@
Map<DirectoryProvider, LuceneIndexingParameters> dirProviderIndexingParams;
public SearchFactoryImplementor buildSearchFactory() {
- if (rootFactory == null) {
- if (classes.size() > 0) {
- throw new SearchException( "Cannot add a class if the original SearchFactory is
not passed");
+ SearchFactoryImplementor searchFactoryImplementor;
+ if ( rootFactory == null ) {
+ if ( classes.size() > 0 ) {
+ throw new SearchException( "Cannot add a class if the original SearchFactory is
not passed" );
}
- return buildNewSearchFactory();
+ searchFactoryImplementor = buildNewSearchFactory();
}
else {
- return buildIncrementalSearchFactory();
+ searchFactoryImplementor = buildIncrementalSearchFactory();
}
+
+ String enableJMX = configurationProperties.getProperty( Environment.JMX_ENABLED );
+ if ( "true".equalsIgnoreCase( enableJMX ) ) {
+ enableJMXStatistics( searchFactoryImplementor );
+ }
+ return searchFactoryImplementor;
}
+ private void enableJMXStatistics(SearchFactoryImplementor searchFactoryImplementor) {
+ HibernateSearchConfigInfo statsBean = new HibernateSearchConfigInfo(
searchFactoryImplementor );
+ ObjectName name = createObjectName(
HibernateSearchConfigInfoMBean.CONFIG_MBEAN_OBJECT_NAME );
+ registerMBean( statsBean, name );
+
+ // if we have a JNDI bound SessionFactory we can also enable the index control bean
+ if ( StringHelper.isNotEmpty( configurationProperties.getProperty(
"hibernate.session_factory_name" ) ) ) {
+ HibernateSearchIndexCtrl indexCtrlBean = new HibernateSearchIndexCtrl(
configurationProperties );
+ name = createObjectName( HibernateSearchIndexCtrl.INDEX_CTRL_MBEAN_OBJECT_NAME );
+ registerMBean( indexCtrlBean, name );
+ }
+ }
+
+ private 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;
+ }
+
+ private void registerMBean(Object stats, 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 );
+ }
+ }
+
+ try {
+ mbs.registerMBean( stats, name );
+ }
+ catch ( Exception e ) {
+ throw new SearchException( "Unable to enable MBean for Hibernate Search", e
);
+ }
+ }
+
private SearchFactoryImplementor buildIncrementalSearchFactory() {
removeClassesAlreadyManaged();
- if (classes.size() == 0) {
+ if ( classes.size() == 0 ) {
return rootFactory;
}
BuildContext buildContext = new BuildContext();
- copyStateFromOldFactory(rootFactory);
+ copyStateFromOldFactory( rootFactory );
//TODO we don't keep the reflectionManager. Is that an issue?
IncrementalSearchConfiguration cfg = new IncrementalSearchConfiguration( classes,
configurationProperties );
reflectionManager = getReflectionManager( cfg );
@@ -152,7 +233,7 @@
//update backend
final BackendQueueProcessorFactory backend = this.backendQueueProcessorFactory;
- if ( backend instanceof UpdatableBackendQueueProcessorFactory) {
+ if ( backend instanceof UpdatableBackendQueueProcessorFactory ) {
final UpdatableBackendQueueProcessorFactory updatableBackend = (
UpdatableBackendQueueProcessorFactory ) backend;
updatableBackend.updateDirectoryProviders( this.dirProviderData.keySet(), buildContext
);
}
@@ -168,13 +249,13 @@
private void removeClassesAlreadyManaged() {
Set<Class<?>> remove = new HashSet<Class<?>>();
final Map<Class<?>, DocumentBuilderContainedEntity<?>>
containedEntities = rootFactory.getDocumentBuildersContainedEntities();
- final Map<Class<?>, DocumentBuilderIndexedEntity<?>> indexedEntities
= rootFactory.getDocumentBuildersIndexedEntities();
- for (Class<?> entity : classes) {
- if ( indexedEntities.containsKey( entity ) || containedEntities.containsKey(entity) )
{
+ final Map<Class<?>, DocumentBuilderIndexedEntity<?>> indexedEntities
= rootFactory.getDocumentBuildersIndexedEntities();
+ for ( Class<?> entity : classes ) {
+ if ( indexedEntities.containsKey( entity ) || containedEntities.containsKey( entity )
) {
remove.add( entity );
}
}
- for(Class<?> entity : remove) {
+ for ( Class<?> entity : remove ) {
classes.remove( entity );
}
}
@@ -202,16 +283,18 @@
configurationProperties = cfg.getProperties();
errorHandler = createErrorHandler( configurationProperties );
- reflectionManager = getReflectionManager(cfg);
+ reflectionManager = getReflectionManager( cfg );
BuildContext buildContext = new BuildContext();
- final SearchMapping mapping = SearchMappingBuilder.getSearchMapping(cfg);
- if ( mapping != null) {
- if ( ! ( reflectionManager instanceof MetadataProviderInjector )) {
- throw new SearchException("Programmatic mapping model used but ReflectionManager
does not implement "
- + MetadataProviderInjector.class.getName() );
+ final SearchMapping mapping = SearchMappingBuilder.getSearchMapping( cfg );
+ if ( mapping != null ) {
+ if ( !( reflectionManager instanceof MetadataProviderInjector ) ) {
+ throw new SearchException(
+ "Programmatic mapping model used but ReflectionManager does not implement
"
+ + MetadataProviderInjector.class.getName()
+ );
}
- MetadataProviderInjector injector = (MetadataProviderInjector) reflectionManager;
+ MetadataProviderInjector injector = ( MetadataProviderInjector ) reflectionManager;
MetadataProvider original = injector.getMetadataProvider();
injector.setMetadataProvider( new MappingModelMetadataProvider( original, mapping )
);
}
@@ -248,10 +331,12 @@
DocumentBuilderIndexedEntity<?> documentBuilder =
documentBuildersIndexedEntities.get( indexedType );
Similarity similarity = documentBuilder.getSimilarity();
Similarity prevSimilarity = directoryConfiguration.getSimilarity();
- if ( prevSimilarity != null && ! prevSimilarity.getClass().equals(
similarity.getClass() ) ) {
- throw new SearchException( "Multiple entities are sharing the same index but
are declaring an " +
- "inconsistent Similarity. When overrriding default Similarity make sure that
all types sharing a same index " +
- "declare the same Similarity implementation." );
+ if ( prevSimilarity != null && !prevSimilarity.getClass().equals(
similarity.getClass() ) ) {
+ throw new SearchException(
+ "Multiple entities are sharing the same index but are declaring an " +
+ "inconsistent Similarity. When overrriding default Similarity make sure
that all types sharing a same index " +
+ "declare the same Similarity implementation."
+ );
}
else {
directoryConfiguration.setSimilarity( similarity );
@@ -267,8 +352,10 @@
filterCachingStrategy = new MRUFilterCachingStrategy();
}
else {
- filterCachingStrategy = PluginLoader.instanceFromName( FilterCachingStrategy.class,
- impl, ImmutableSearchFactory.class, "filterCachingStrategy" );
+ filterCachingStrategy = PluginLoader.instanceFromName(
+ FilterCachingStrategy.class,
+ impl, ImmutableSearchFactory.class, "filterCachingStrategy"
+ );
}
filterCachingStrategy.initialize( properties );
return filterCachingStrategy;
@@ -289,20 +376,21 @@
* Initialize the document builder
* This algorithm seems to be safe for incremental search factories.
*/
+
private void initDocumentBuilders(SearchConfiguration cfg, ReflectionManager
reflectionManager, BuildContext buildContext) {
ConfigContext context = new ConfigContext( cfg );
Iterator<Class<?>> iter = cfg.getClassMappings();
DirectoryProviderFactory factory = new DirectoryProviderFactory();
- initProgrammaticAnalyzers(context, reflectionManager);
- initProgrammaticallyDefinedFilterDef(reflectionManager);
+ initProgrammaticAnalyzers( context, reflectionManager );
+ initProgrammaticallyDefinedFilterDef( reflectionManager );
while ( iter.hasNext() ) {
Class<?> mappedClass = iter.next();
if ( mappedClass == null ) {
continue;
}
- @SuppressWarnings( "unchecked" )
+ @SuppressWarnings("unchecked")
XClass mappedXClass = reflectionManager.toXClass( mappedClass );
if ( mappedXClass == null ) {
continue;
@@ -367,7 +455,7 @@
);
}
- bindFullTextFilterDef(defAnn);
+ bindFullTextFilterDef( defAnn );
}
private void bindFullTextFilterDef(FullTextFilterDef defAnn) {
@@ -419,10 +507,10 @@
private void initProgrammaticAnalyzers(ConfigContext context, ReflectionManager
reflectionManager) {
final Map defaults = reflectionManager.getDefaults();
- if (defaults != null) {
- AnalyzerDef[] defs = (AnalyzerDef[]) defaults.get( AnalyzerDefs.class );
+ if ( defaults != null ) {
+ AnalyzerDef[] defs = ( AnalyzerDef[] ) defaults.get( AnalyzerDefs.class );
if ( defs != null ) {
- for (AnalyzerDef def : defs) {
+ for ( AnalyzerDef def : defs ) {
context.addAnalyzerDef( def );
}
}
@@ -431,13 +519,13 @@
private void initProgrammaticallyDefinedFilterDef(ReflectionManager reflectionManager)
{
@SuppressWarnings("unchecked") Map defaults =
reflectionManager.getDefaults();
- FullTextFilterDef[] filterDefs = (FullTextFilterDef[]) defaults.get(
FullTextFilterDefs.class);
- if (filterDefs != null && filterDefs.length != 0) {
- for (FullTextFilterDef defAnn : filterDefs) {
+ FullTextFilterDef[] filterDefs = ( FullTextFilterDef[] ) defaults.get(
FullTextFilterDefs.class );
+ if ( filterDefs != null && filterDefs.length != 0 ) {
+ for ( FullTextFilterDef defAnn : filterDefs ) {
if ( filterDefinitions.containsKey( defAnn.name() ) ) {
- throw new SearchException("Multiple definition of
@FullTextFilterDef.name=" + defAnn.name());
+ throw new SearchException( "Multiple definition of
@FullTextFilterDef.name=" + defAnn.name() );
}
- bindFullTextFilterDef(defAnn);
+ bindFullTextFilterDef( defAnn );
}
}
}
@@ -451,8 +539,10 @@
return new LogErrorHandler();
}
else {
- return PluginLoader.instanceFromName( ErrorHandler.class, errorHandlerClassName,
- ImmutableSearchFactory.class, "Error Handler" );
+ return PluginLoader.instanceFromName(
+ ErrorHandler.class, errorHandlerClassName,
+ ImmutableSearchFactory.class, "Error Handler"
+ );
}
}
@@ -534,7 +624,9 @@
public Similarity getSimilarity(DirectoryProvider<?> provider) {
Similarity similarity = dirProviderData.get( provider ).getSimilarity();
- if ( similarity == null ) throw new SearchException( "Assertion error: a
similarity should be defined for each provider" );
+ if ( similarity == null ) {
+ throw new SearchException( "Assertion error: a similarity should be defined for
each provider" );
+ }
return similarity;
}
@@ -550,6 +642,6 @@
public <T> DocumentBuilderIndexedEntity<T>
getDocumentBuilderIndexedEntity(Class<T> entityType) {
return ( DocumentBuilderIndexedEntity<T> ) documentBuildersIndexedEntities.get(
entityType );
}
-
+
}
}
Added:
search/trunk/hibernate-search/src/main/java/org/hibernate/search/jmx/HibernateSearchConfigInfo.java
===================================================================
---
search/trunk/hibernate-search/src/main/java/org/hibernate/search/jmx/HibernateSearchConfigInfo.java
(rev 0)
+++
search/trunk/hibernate-search/src/main/java/org/hibernate/search/jmx/HibernateSearchConfigInfo.java 2010-07-05
14:46:01 UTC (rev 19897)
@@ -0,0 +1,131 @@
+/*
+ * 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.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.index.Term;
+import org.apache.lucene.search.BooleanClause;
+import org.apache.lucene.search.BooleanQuery;
+import org.apache.lucene.search.IndexSearcher;
+import org.apache.lucene.search.MatchAllDocsQuery;
+import org.apache.lucene.search.TermQuery;
+import org.apache.lucene.search.TopDocs;
+
+import org.hibernate.search.ProjectionConstants;
+import org.hibernate.search.engine.SearchFactoryImplementor;
+import org.hibernate.search.reader.ReaderProvider;
+import org.hibernate.search.store.DirectoryProvider;
+import org.hibernate.util.ReflectHelper;
+
+/**
+ * Implementation of the {@code HibernateSearchConfigInfoMBean} JMX attributes and
operations.
+ *
+ * @author Hardy Ferentschik
+ */
+public class HibernateSearchConfigInfo implements HibernateSearchConfigInfoMBean {
+
+ private final SearchFactoryImplementor searchFactoryImplementor;
+
+ public HibernateSearchConfigInfo(SearchFactoryImplementor searchFactoryImplementor) {
+ this.searchFactoryImplementor = searchFactoryImplementor;
+ }
+
+ public Set<String> getIndexedClassNames() {
+ Set<String> indexedClasses = new HashSet<String>();
+ for ( Class clazz :
searchFactoryImplementor.getDocumentBuildersIndexedEntities().keySet() ) {
+ indexedClasses.add( clazz.getName() );
+ }
+ return indexedClasses;
+ }
+
+ public String getIndexingStrategy() {
+ return searchFactoryImplementor.getIndexingStrategy();
+ }
+
+ public int getNumberOfIndexedEntities(String entity) {
+ Class<?> clazz = getEntityClass( entity );
+ DirectoryProvider[] directoryProviders =
searchFactoryImplementor.getDirectoryProviders( clazz );
+ ReaderProvider readerProvider = searchFactoryImplementor.getReaderProvider();
+
+ int count = 0;
+ for ( DirectoryProvider directoryProvider : directoryProviders ) {
+ IndexReader reader = readerProvider.openReader( directoryProvider );
+ IndexSearcher searcher = new IndexSearcher( reader );
+ BooleanQuery boolQuery = new BooleanQuery();
+ boolQuery.add( new MatchAllDocsQuery(), BooleanClause.Occur.MUST );
+ boolQuery.add(
+ new TermQuery( new Term( ProjectionConstants.OBJECT_CLASS, entity ) ),
BooleanClause.Occur.MUST
+ );
+ try {
+ TopDocs topdocs = searcher.search( boolQuery, 1 );
+ count += topdocs.totalHits;
+ }
+ catch ( IOException e ) {
+ throw new RuntimeException( "Unable to execute count query for entity " +
entity, e );
+ }
+ finally {
+ readerProvider.closeReader( reader );
+ }
+ }
+ return count;
+ }
+
+ public Map<String, Integer> indexedEntitiesCount() {
+ Map<String, Integer> countPerEntity = new HashMap<String, Integer>();
+ for ( String className : getIndexedClassNames() ) {
+ countPerEntity.put( className, getNumberOfIndexedEntities( className ) );
+ }
+ return countPerEntity;
+ }
+
+ public List<String> getIndexingParameters(String entity) {
+ Class<?> clazz = getEntityClass( entity );
+ List<String> indexingParameters = new ArrayList<String>();
+ for ( DirectoryProvider directoryProvider :
searchFactoryImplementor.getDirectoryProviders( clazz ) ) {
+ indexingParameters.add( searchFactoryImplementor.getIndexingParameters(
directoryProvider ).toString() );
+ }
+ return indexingParameters;
+ }
+
+ private Class<?> getEntityClass(String entity) {
+ Class<?> clazz;
+ try {
+ clazz = ReflectHelper.classForName( entity, HibernateSearchConfigInfo.class );
+ }
+ catch ( ClassNotFoundException e ) {
+ throw new IllegalArgumentException( entity + "not a indexed entity" );
+ }
+ return clazz;
+ }
+}
+
+
Added:
search/trunk/hibernate-search/src/main/java/org/hibernate/search/jmx/HibernateSearchConfigInfoMBean.java
===================================================================
---
search/trunk/hibernate-search/src/main/java/org/hibernate/search/jmx/HibernateSearchConfigInfoMBean.java
(rev 0)
+++
search/trunk/hibernate-search/src/main/java/org/hibernate/search/jmx/HibernateSearchConfigInfoMBean.java 2010-07-05
14:46:01 UTC (rev 19897)
@@ -0,0 +1,83 @@
+/*
+ * 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.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Defines the Hibernate Search exposed JMX attributes and operations for index
configuration.
+ *
+ * @author Hardy Ferentschik
+ */
+public interface HibernateSearchConfigInfoMBean {
+
+ public static final String CONFIG_MBEAN_OBJECT_NAME =
"org.hibernate.search.jmx:type=HibernateSearchConfigInfoMBean";
+
+ /**
+ * Returns a list of all indexed classes.
+ *
+ * @return list of all indexed classes
+ */
+ Set<String> getIndexedClassNames();
+
+ /**
+ * Returns the indexing strategy - <i>manual</i> vs. event
<i>event</i>.
+ *
+ * @return the indexing strategy
+ */
+ String getIndexingStrategy();
+
+ /**
+ * Returns the number of documents for the given entity.
+ *
+ * @param entity the fqc of the entity
+ *
+ * @return number of documents for the specified entity name
+ *
+ * @throws IllegalArgumentException in case the entity name is not valid
+ */
+ int getNumberOfIndexedEntities(String entity);
+
+ /**
+ * A list of string representations of the indexing parameters for each directory of the
specified entity.
+ * Defaults are not displayed, but only parameters which are explicitly set via the
configuration.
+ *
+ * @param entity the fqc of the entity
+ *
+ * @return A list of string representations of the indexing parameters for each
directory of the specified entity
+ *
+ * @throws IllegalArgumentException in case the entity name is not valid
+ */
+ List<String> getIndexingParameters(String entity);
+
+ /**
+ * Returns a map of all indexed entities and their document count in the index.
+ *
+ * @return a map of all indexed entities and their document count. The map key is the
fqc of the entity and
+ * the map value is the document count.
+ */
+ Map<String, Integer> indexedEntitiesCount();
+}
Added:
search/trunk/hibernate-search/src/main/java/org/hibernate/search/jmx/HibernateSearchIndexCtrl.java
===================================================================
---
search/trunk/hibernate-search/src/main/java/org/hibernate/search/jmx/HibernateSearchIndexCtrl.java
(rev 0)
+++
search/trunk/hibernate-search/src/main/java/org/hibernate/search/jmx/HibernateSearchIndexCtrl.java 2010-07-05
14:46:01 UTC (rev 19897)
@@ -0,0 +1,115 @@
+/*
+ * 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.util.Properties;
+import javax.naming.Context;
+import javax.naming.InitialContext;
+
+import org.hibernate.CacheMode;
+import org.hibernate.Session;
+import org.hibernate.SessionFactory;
+import org.hibernate.search.FullTextSession;
+import org.hibernate.search.Search;
+import org.hibernate.search.util.JNDIHelper;
+import org.hibernate.util.ReflectHelper;
+
+
+/**
+ * Implementation of the {@code HibernateSearchIndexCtrlMBean} JMX attributes and
operations.
+ *
+ * @author Hardy Ferentschik
+ */
+public class HibernateSearchIndexCtrl implements HibernateSearchIndexCtrlMBean {
+ private static final String HIBERNATE_JNDI_PREFIX = "hibernate.jndi.";
+
+ private final Properties jndiProperties;
+ private final String sessionFactoryJndiName;
+
+ public HibernateSearchIndexCtrl(Properties props) {
+ this.sessionFactoryJndiName = props.getProperty(
"hibernate.session_factory_name" );
+ this.jndiProperties = JNDIHelper.getJndiProperties( props, HIBERNATE_JNDI_PREFIX );
+ }
+
+ public void index(String entity) {
+ Class<?> clazz = getEntityClass( entity );
+
+ SessionFactory factory = getSessionFactory();
+ Session session = factory.openSession();
+ FullTextSession fulltextSession = Search.getFullTextSession( session );
+ try {
+ fulltextSession.createIndexer( clazz )
+ .batchSizeToLoadObjects( 25 )
+ .cacheMode( CacheMode.NORMAL )
+ .threadsToLoadObjects( 5 )
+ .threadsForSubsequentFetching( 20 )
+ .startAndWait();
+ }
+ catch ( InterruptedException e ) {
+ throw new RuntimeException( "Unable to complete indexing" );
+ }
+ session.close();
+ }
+
+ public void purge(String entity) {
+ Class<?> clazz = getEntityClass( entity );
+
+ SessionFactory factory = getSessionFactory();
+ Session session = factory.openSession();
+ FullTextSession fullTextSession = Search.getFullTextSession( session );
+ fullTextSession.beginTransaction();
+ fullTextSession.purgeAll( clazz );
+ fullTextSession.getTransaction().commit();
+ session.close();
+ }
+
+ private Class<?> getEntityClass(String entity) {
+ Class<?> clazz;
+ try {
+ clazz = ReflectHelper.classForName( entity, HibernateSearchIndexCtrl.class );
+ }
+ catch ( ClassNotFoundException e ) {
+ throw new IllegalArgumentException( entity + "not a indexed entity" );
+ }
+ return clazz;
+ }
+
+ private SessionFactory getSessionFactory() {
+ try {
+ Context initialContext;
+ if ( jndiProperties.isEmpty() ) {
+ initialContext = new InitialContext();
+ }
+ else {
+ initialContext = new InitialContext( jndiProperties );
+ }
+ return ( SessionFactory ) initialContext.lookup( sessionFactoryJndiName );
+ }
+ catch ( Exception e ) {
+ throw new UnsupportedOperationException(
+ "In order for this operation to work the SessionFactory must be bound to
JNDI"
+ );
+ }
+ }
+}
\ No newline at end of file
Added:
search/trunk/hibernate-search/src/main/java/org/hibernate/search/jmx/HibernateSearchIndexCtrlMBean.java
===================================================================
---
search/trunk/hibernate-search/src/main/java/org/hibernate/search/jmx/HibernateSearchIndexCtrlMBean.java
(rev 0)
+++
search/trunk/hibernate-search/src/main/java/org/hibernate/search/jmx/HibernateSearchIndexCtrlMBean.java 2010-07-05
14:46:01 UTC (rev 19897)
@@ -0,0 +1,62 @@
+/*
+ * 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;
+
+/**
+ * Defines the Hibernate Search exposed JMX attributes and operations for index creation
and purging.
+ *
+ * @author Hardy Ferentschik
+ */
+public interface HibernateSearchIndexCtrlMBean {
+
+ public static final String INDEX_CTRL_MBEAN_OBJECT_NAME =
"org.hibernate.search.jmx:type=HibernateSearchIndexCtrlMBean";
+
+ /**
+ * Index the specified entity using the mass indexer.
+ * <p><b>Note:<br/>
+ * This method is only available if the Hibernate {@code SessionFactory}
+ * is available via JNDI.
+ * </p>
+ *
+ * @param entity The fqc of the entity to index
+ *
+ * @throws IllegalArgumentException in case the entity name is not valid
+ * @throws UnsupportedOperationException in case the Hibernate {@code SessionFactory} is
not bound via JNDI.
+ */
+ void index(String entity);
+
+ /**
+ * Purge the index of the specified entity.
+ * <p><b>Note:<br/>
+ * This method is only available if the Hibernate {@code SessionFactory}
+ * is available via JNDI.
+ * </p>
+ *
+ * @param entity The fqc of the entity to index
+ *
+ * @throws IllegalArgumentException in case the entity name is not valid
+ * @throws UnsupportedOperationException in case the Hibernate {@code SessionFactory} is
not bound via JNDI.
+ */
+ void purge(String entity);
+}
\ No newline at end of file
Added:
search/trunk/hibernate-search/src/main/java/org/hibernate/search/util/JNDIHelper.java
===================================================================
--- search/trunk/hibernate-search/src/main/java/org/hibernate/search/util/JNDIHelper.java
(rev 0)
+++
search/trunk/hibernate-search/src/main/java/org/hibernate/search/util/JNDIHelper.java 2010-07-05
14:46:01 UTC (rev 19897)
@@ -0,0 +1,112 @@
+/*
+ * 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.util;
+
+import java.util.HashSet;
+import java.util.Properties;
+import javax.naming.Context;
+import javax.naming.InitialContext;
+import javax.naming.NamingException;
+
+/**
+ * Helper class for creating an JNDI {@code InitialContext}.
+ *
+ * @author Hardy Ferentschik
+ */
+public class JNDIHelper {
+ private JNDIHelper() {
+ }
+
+ /**
+ * Creates an initial context
+ *
+ * @param properties Configuration properties to check for JNDI specific properties
+ * @param prefix The prefix used to designate JDNI properties. If a property from {@code
property} contains
+ * a property which matches the prefix, the prefix gets removed and the property passed
to the initial context creation.
+ *
+ * @return the initial context
+ *
+ * @throws NamingException in case an error occurs creating the {@code InitialContext}
+ */
+ public static InitialContext getInitialContext(Properties properties, String prefix)
throws NamingException {
+ Properties jndiProps = getJndiProperties( properties, prefix );
+ if ( jndiProps.size() == 0 ) {
+ return new InitialContext();
+ }
+ else {
+ return new InitialContext( jndiProps );
+ }
+ }
+
+ public static Properties getJndiProperties(Properties properties, String prefix) {
+
+ HashSet<String> specialProps = new HashSet<String>();
+ specialProps.add( prefix + "class" );
+ specialProps.add( prefix + "url" );
+
+ Properties result = addJNDIProperties( properties, prefix, specialProps );
+
+ handleSpecialPropertyTranslation( properties, prefix + "class", result,
Context.INITIAL_CONTEXT_FACTORY );
+ handleSpecialPropertyTranslation( properties, prefix + "url", result,
Context.PROVIDER_URL );
+
+ return result;
+ }
+
+ /**
+ * Creates a new {@code Properties} instance with all properties from {@code properties}
which start with the given
+ *
+ * @param properties the original properties
+ * @param prefix the prefix indicating JNDI specific properties
+ * @param specialProps a set of property names to ignore
+ *
+ * @return Creates a new {@code Properties} instance with JNDI specific properties
+ *
+ * @{code prefix}. In the new instance the prefix is removed. If a property matches a
value in {@code specialProps}
+ * it gets ignored.
+ */
+ private static Properties addJNDIProperties(Properties properties, String prefix,
HashSet<String> specialProps) {
+ Properties result = new Properties();
+ for ( Object property : properties.keySet() ) {
+ if ( property instanceof String ) {
+ String s = ( String ) property;
+ if ( s.indexOf( prefix ) > -1 && !specialProps.contains( s ) ) {
+ result.setProperty( s.substring( prefix.length() ), properties.getProperty( s ) );
+ }
+ }
+ }
+ return result;
+ }
+
+ private static void handleSpecialPropertyTranslation(Properties originalProperties,
String oldKey, Properties newProperties, String newKey) {
+ String value = originalProperties.getProperty( oldKey );
+ // we want to be able to just use the defaults,
+ // if JNDI environment properties are not supplied
+ // so don't put null in anywhere
+ if ( value != null ) {
+ newProperties.put( newKey, value );
+ }
+ }
+}
+
+
Modified:
search/trunk/hibernate-search/src/test/java/org/hibernate/search/test/SearchTestCase.java
===================================================================
---
search/trunk/hibernate-search/src/test/java/org/hibernate/search/test/SearchTestCase.java 2010-07-05
14:30:38 UTC (rev 19896)
+++
search/trunk/hibernate-search/src/test/java/org/hibernate/search/test/SearchTestCase.java 2010-07-05
14:46:01 UTC (rev 19897)
@@ -26,6 +26,7 @@
import java.io.File;
import java.io.InputStream;
+import java.net.URL;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.KeywordAnalyzer;
@@ -62,14 +63,14 @@
public abstract class SearchTestCase extends TestCase {
private static final Logger log = org.hibernate.search.util.LoggerFactory.make();
-
+
public static final Analyzer standardAnalyzer = new StandardAnalyzer(
getTargetLuceneVersion() );
public static final Analyzer stopAnalyzer = new StopAnalyzer( getTargetLuceneVersion()
);
public static final Analyzer simpleAnalyzer = new SimpleAnalyzer();
public static final Analyzer keywordAnalyzer = new KeywordAnalyzer();
private static File indexDir;
-
+
private SearchFactoryImplementor searchFactory;
static {
@@ -134,12 +135,12 @@
tx.commit();
s.close();
}
-
+
protected SearchFactory getSearchFactory() {
if ( searchFactory == null ) {
Session session = openSession();
FullTextSession fullTextSession = Search.getFullTextSession( session );
- searchFactory = ( SearchFactoryImplementor) fullTextSession.getSearchFactory();
+ searchFactory = ( SearchFactoryImplementor ) fullTextSession.getSearchFactory();
fullTextSession.close();
}
return searchFactory;
@@ -195,9 +196,28 @@
protected static File getIndexDir() {
return indexDir;
}
-
+
public static Version getTargetLuceneVersion() {
return Version.LUCENE_29;
}
-
+
+ /**
+ * Returns the target directory of the build.
+ *
+ * @return the target directory of the build
+ */
+ public File getTargetDir() {
+ ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
+ // get a URL reference to something we now is part of the classpath (us)
+ URL myUrl = contextClassLoader.getResource( SearchTestCase.class.getName().replace(
'.', '/' ) + ".class" );
+ File myPath = new File( myUrl.getFile() );
+ // navigate back to '/target'
+ return myPath
+ .getParentFile() // target/classes/org/hibernate/search/test
+ .getParentFile() // target/classes/org/hibernate/search
+ .getParentFile() // target/classes/org/hibernate/
+ .getParentFile() // target/classes/org
+ .getParentFile() // target/classes/
+ .getParentFile(); // target
+ }
}
Modified:
search/trunk/hibernate-search/src/test/java/org/hibernate/search/test/jms/master/JMSMasterTest.java
===================================================================
---
search/trunk/hibernate-search/src/test/java/org/hibernate/search/test/jms/master/JMSMasterTest.java 2010-07-05
14:30:38 UTC (rev 19896)
+++
search/trunk/hibernate-search/src/test/java/org/hibernate/search/test/jms/master/JMSMasterTest.java 2010-07-05
14:46:01 UTC (rev 19897)
@@ -29,6 +29,7 @@
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
+import java.util.Properties;
import javax.jms.MessageConsumer;
import javax.jms.ObjectMessage;
import javax.jms.Queue;
@@ -37,12 +38,14 @@
import javax.jms.QueueSender;
import javax.jms.QueueSession;
import javax.naming.Context;
+import javax.naming.NamingException;
import org.apache.activemq.broker.BrokerService;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.queryParser.QueryParser;
import org.apache.lucene.search.Query;
+
import org.hibernate.Session;
import org.hibernate.cfg.Configuration;
import org.hibernate.search.Environment;
@@ -114,13 +117,13 @@
}
private Queue getMessageQueue() throws Exception {
- Context ctx = new javax.naming.InitialContext();
+ Context ctx = getJndiInitialContext();
return ( Queue ) ctx.lookup( QUEUE_NAME );
}
private QueueSession getQueueSession() throws Exception {
if ( queueSession == null ) {
- Context ctx = new javax.naming.InitialContext();
+ Context ctx = getJndiInitialContext();
QueueConnectionFactory factory = ( QueueConnectionFactory ) ctx.lookup(
CONNECTION_FACTORY_NAME );
QueueConnection conn = factory.createQueueConnection();
conn.start();
@@ -130,6 +133,18 @@
return queueSession;
}
+ private Context getJndiInitialContext() throws NamingException {
+ Properties props = new Properties();
+ props.setProperty(
+ Context.INITIAL_CONTEXT_FACTORY,
"org.apache.activemq.jndi.ActiveMQInitialContextFactory"
+ );
+ props.setProperty( Context.PROVIDER_URL, "vm://localhost" );
+ props.setProperty( "connectionFactoryNames", "ConnectionFactory,
java:/ConnectionFactory" );
+ props.setProperty( "queue.queue/searchtest", "searchQueue" );
+ Context ctx = new javax.naming.InitialContext( props );
+ return ctx;
+ }
+
/**
* Manually create the work queue. This lists gets send by the Slaves to the Master for
indexing.
*
@@ -194,7 +209,7 @@
protected void configure(Configuration cfg) {
super.configure( cfg );
- // explcitily set the backend even though lucene is default.
+ // explicitly set the backend even though lucene is default.
cfg.setProperty( Environment.WORKER_BACKEND, "lucene" );
}
Modified:
search/trunk/hibernate-search/src/test/java/org/hibernate/search/test/jms/slave/JMSSlaveTest.java
===================================================================
---
search/trunk/hibernate-search/src/test/java/org/hibernate/search/test/jms/slave/JMSSlaveTest.java 2010-07-05
14:30:38 UTC (rev 19896)
+++
search/trunk/hibernate-search/src/test/java/org/hibernate/search/test/jms/slave/JMSSlaveTest.java 2010-07-05
14:46:01 UTC (rev 19897)
@@ -24,21 +24,23 @@
*/
package org.hibernate.search.test.jms.slave;
+import java.util.Properties;
import javax.jms.MessageConsumer;
import javax.jms.Queue;
import javax.jms.QueueConnection;
import javax.jms.QueueConnectionFactory;
import javax.jms.QueueSession;
import javax.naming.Context;
+import javax.naming.NamingException;
import org.apache.activemq.broker.BrokerService;
+import org.hibernate.Session;
+import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.hibernate.search.Environment;
import org.hibernate.search.backend.impl.jms.JMSBackendQueueProcessorFactory;
import org.hibernate.search.test.SearchTestCase;
-import org.hibernate.Session;
-import org.hibernate.Transaction;
/**
* Checks that the Slave in a JMS configuration proplerly places index jobs onto the
queue.
@@ -68,7 +70,7 @@
public void testMessageSend() throws Exception {
registerMessageListener();
SearchQueueChecker.reset();
-
+
Session s = openSession();
Transaction tx = s.beginTransaction();
TShirt ts = new TShirt();
@@ -82,7 +84,7 @@
tx.commit();
//need to sleep for the message consumption
- Thread.sleep(500);
+ Thread.sleep( 500 );
assertEquals( 1, SearchQueueChecker.queues );
assertEquals( 2, SearchQueueChecker.works );
@@ -90,12 +92,12 @@
SearchQueueChecker.reset();
s = openSession();
tx = s.beginTransaction();
- ts = (TShirt) s.get( TShirt.class, ts.getId() );
+ ts = ( TShirt ) s.get( TShirt.class, ts.getId() );
ts.setLogo( "Peter pan" );
tx.commit();
//need to sleep for the message consumption
- Thread.sleep(500);
+ Thread.sleep( 500 );
assertEquals( 1, SearchQueueChecker.queues );
assertEquals( 2, SearchQueueChecker.works ); //one update = 2 works
@@ -108,8 +110,8 @@
tx.commit();
//Need to sleep for the message consumption
- Thread.sleep(500);
-
+ Thread.sleep( 500 );
+
assertEquals( 1, SearchQueueChecker.queues );
assertEquals( 2, SearchQueueChecker.works );
s.close();
@@ -137,13 +139,13 @@
}
private Queue getMessageQueue() throws Exception {
- Context ctx = new javax.naming.InitialContext();
+ Context ctx = getJndiInitialContext();
return ( Queue ) ctx.lookup( QUEUE_NAME );
}
private QueueSession getQueueSession() throws Exception {
if ( queueSession == null ) {
- Context ctx = new javax.naming.InitialContext();
+ Context ctx = getJndiInitialContext();
QueueConnectionFactory factory = ( QueueConnectionFactory ) ctx.lookup(
CONNECTION_FACTORY_NAME );
QueueConnection conn = factory.createQueueConnection();
conn.start();
@@ -158,6 +160,15 @@
cfg.setProperty( Environment.WORKER_BACKEND, "jms" );
cfg.setProperty( JMSBackendQueueProcessorFactory.JMS_CONNECTION_FACTORY,
CONNECTION_FACTORY_NAME );
cfg.setProperty( JMSBackendQueueProcessorFactory.JMS_QUEUE, QUEUE_NAME );
+
+ // use the hibernate.search.worker.jndi prefix to pass a whole bunch of jndi properties
to create the InitialContext
+ // for the queue processor
+ cfg.setProperty(
+ "hibernate.search.worker.jndi.class",
"org.apache.activemq.jndi.ActiveMQInitialContextFactory"
+ );
+ cfg.setProperty( "hibernate.search.worker.jndi.url",
"vm://localhost" );
+ cfg.setProperty( "hibernate.search.worker.jndi.connectionFactoryNames",
"ConnectionFactory, java:/ConnectionFactory" );
+ cfg.setProperty( "hibernate.search.worker.jndi.queue.queue/searchtest",
"searchQueue" );
}
protected Class<?>[] getMappings() {
@@ -165,4 +176,17 @@
TShirt.class
};
}
+
+ private Context getJndiInitialContext() throws NamingException {
+ Properties props = new Properties();
+ props.setProperty(
+ Context.INITIAL_CONTEXT_FACTORY,
"org.apache.activemq.jndi.ActiveMQInitialContextFactory"
+ );
+ props.setProperty( Context.PROVIDER_URL, "vm://localhost" );
+ props.setProperty( "connectionFactoryNames", "ConnectionFactory,
java:/ConnectionFactory" );
+ props.setProperty( "queue.queue/searchtest", "searchQueue" );
+
+ Context ctx = new javax.naming.InitialContext( props );
+ return ctx;
+ }
}
Added:
search/trunk/hibernate-search/src/test/java/org/hibernate/search/test/jmx/ConfigInfoMBeanTest.java
===================================================================
---
search/trunk/hibernate-search/src/test/java/org/hibernate/search/test/jmx/ConfigInfoMBeanTest.java
(rev 0)
+++
search/trunk/hibernate-search/src/test/java/org/hibernate/search/test/jmx/ConfigInfoMBeanTest.java 2010-07-05
14:46:01 UTC (rev 19897)
@@ -0,0 +1,147 @@
+/*
+ * 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.test.jmx;
+
+import java.lang.management.ManagementFactory;
+import java.util.HashSet;
+import java.util.Set;
+import javax.management.InstanceNotFoundException;
+import javax.management.MBeanAttributeInfo;
+import javax.management.MBeanException;
+import javax.management.MBeanInfo;
+import javax.management.MBeanOperationInfo;
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+import javax.management.ReflectionException;
+
+import org.hibernate.Transaction;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.search.Environment;
+import org.hibernate.search.FullTextSession;
+import org.hibernate.search.Search;
+import org.hibernate.search.jmx.HibernateSearchConfigInfoMBean;
+import org.hibernate.search.test.SearchTestCase;
+
+/**
+ * @author Hardy Ferentschik
+ */
+public class ConfigInfoMBeanTest extends SearchTestCase {
+ MBeanServer mbeanServer;
+ ObjectName configBeanObjectName;
+
+ public void testConfigInfoMBeanRegistered() throws Exception {
+ assertTrue(
+ "With the right property set the Search MBean should be registered",
+ mbeanServer.isRegistered( configBeanObjectName )
+ );
+ }
+
+ public void testAttributesAndOperations() throws Exception {
+ MBeanInfo info = mbeanServer.getMBeanInfo( configBeanObjectName );
+ MBeanAttributeInfo[] attributes = info.getAttributes();
+ assertEquals( "Wrong number of attributes", 2, attributes.length );
+ Set<String> attributeNames = new HashSet<String>();
+ attributeNames.add( "IndexedClassNames" );
+ attributeNames.add( "IndexingStrategy" );
+ for ( MBeanAttributeInfo attribute : attributes ) {
+ assertTrue( attributeNames.contains( attribute.getName() ) );
+ }
+
+ MBeanOperationInfo[] operations = info.getOperations();
+ assertEquals( "Wrong number of operations", 3, operations.length );
+ Set<String> operationNames = new HashSet<String>();
+ operationNames.add( "getNumberOfIndexedEntities" );
+ operationNames.add( "indexedEntitiesCount" );
+ operationNames.add( "getIndexingParameters" );
+ for ( MBeanOperationInfo operation : operations ) {
+ assertTrue( operationNames.contains( operation.getName() ) );
+ }
+ }
+
+ public void testIndexingStrategy() throws Exception {
+ assertEquals(
+ "wrong even type", "event", mbeanServer.getAttribute(
configBeanObjectName, "IndexingStrategy" )
+ );
+ }
+
+ public void testIndexedClassNames() throws Exception {
+ assertEquals(
+ "wrong class name",
+ Counter.class.getName(),
+ ( ( Set ) mbeanServer.getAttribute( configBeanObjectName,
"IndexedClassNames" ) ).iterator().next()
+ );
+ }
+
+
+ public void testNumberOfIndexedEntities() throws Exception {
+ assertNumberOfIndexedEntities( Counter.class.getName(), 0 );
+
+ FullTextSession s = Search.getFullTextSession( openSession() );
+ Transaction tx = s.beginTransaction();
+ Counter counter = new Counter();
+ s.save( counter );
+ tx.commit();
+ s.close();
+
+ assertNumberOfIndexedEntities( Counter.class.getName(), 1 );
+ }
+
+ private void assertNumberOfIndexedEntities(String entity, int count)
+ throws InstanceNotFoundException, MBeanException, ReflectionException {
+ assertEquals(
+ "wrong number of indexed entities", count,
+ mbeanServer.invoke(
+ configBeanObjectName,
+ "getNumberOfIndexedEntities",
+ new String[] { entity },
+ new String[] { String.class.getName() }
+ )
+ );
+ }
+
+ protected void setUp() throws Exception {
+ super.setUp();
+ mbeanServer = ManagementFactory.getPlatformMBeanServer();
+ configBeanObjectName = new ObjectName(
HibernateSearchConfigInfoMBean.CONFIG_MBEAN_OBJECT_NAME );
+ }
+
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ if ( mbeanServer.isRegistered( configBeanObjectName ) ) {
+ mbeanServer.unregisterMBean( configBeanObjectName );
+ }
+ }
+
+ protected void configure(Configuration cfg) {
+ super.configure( cfg );
+ cfg.setProperty( Environment.JMX_ENABLED, "true" );
+ }
+
+ @Override
+ protected Class<?>[] getMappings() {
+ return new Class<?>[] { Counter.class };
+ }
+}
+
+
Added:
search/trunk/hibernate-search/src/test/java/org/hibernate/search/test/jmx/Counter.java
===================================================================
---
search/trunk/hibernate-search/src/test/java/org/hibernate/search/test/jmx/Counter.java
(rev 0)
+++
search/trunk/hibernate-search/src/test/java/org/hibernate/search/test/jmx/Counter.java 2010-07-05
14:46:01 UTC (rev 19897)
@@ -0,0 +1,47 @@
+/*
+ * 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.test.jmx;
+
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+
+import org.hibernate.search.annotations.Indexed;
+
+/**
+ * @author Hardy Ferentschik
+ */
+@Entity
+@Indexed
+public class Counter {
+ @Id
+ @GeneratedValue
+ private long id;
+
+ public long getId() {
+ return id;
+ }
+}
+
+
Added:
search/trunk/hibernate-search/src/test/java/org/hibernate/search/test/jmx/IndexCtrlMBeanTest.java
===================================================================
---
search/trunk/hibernate-search/src/test/java/org/hibernate/search/test/jmx/IndexCtrlMBeanTest.java
(rev 0)
+++
search/trunk/hibernate-search/src/test/java/org/hibernate/search/test/jmx/IndexCtrlMBeanTest.java 2010-07-05
14:46:01 UTC (rev 19897)
@@ -0,0 +1,160 @@
+/*
+ * 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.test.jmx;
+
+import java.io.File;
+import java.lang.management.ManagementFactory;
+import java.util.HashSet;
+import java.util.Set;
+import javax.management.InstanceNotFoundException;
+import javax.management.MBeanAttributeInfo;
+import javax.management.MBeanException;
+import javax.management.MBeanInfo;
+import javax.management.MBeanOperationInfo;
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+import javax.management.ReflectionException;
+
+import org.hibernate.Transaction;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.search.Environment;
+import org.hibernate.search.FullTextSession;
+import org.hibernate.search.Search;
+import org.hibernate.search.jmx.HibernateSearchConfigInfoMBean;
+import org.hibernate.search.jmx.HibernateSearchIndexCtrlMBean;
+import org.hibernate.search.test.SearchTestCase;
+
+/**
+ * @author Hardy Ferentschik
+ */
+public class IndexCtrlMBeanTest extends SearchTestCase {
+ MBeanServer mbeanServer;
+ ObjectName configBeanObjectName;
+ ObjectName indexBeanObjectName;
+
+ public void testIndexCtrlMBeanRegistered() throws Exception {
+ assertTrue(
+ "With the right property set the Search MBean should be registered",
+ mbeanServer.isRegistered( indexBeanObjectName )
+ );
+ }
+
+ public void testAttributesAndOperations() throws Exception {
+ MBeanInfo info = mbeanServer.getMBeanInfo( indexBeanObjectName );
+ MBeanAttributeInfo[] attributes = info.getAttributes();
+ assertEquals( "Wrong number of attributes", 0, attributes.length );
+
+ MBeanOperationInfo[] operations = info.getOperations();
+ assertEquals( "Wrong number of operations", 2, operations.length );
+ Set<String> operationNames = new HashSet<String>();
+ operationNames.add( "index" );
+ operationNames.add( "purge" );
+ for ( MBeanOperationInfo operation : operations ) {
+ assertTrue( operationNames.contains( operation.getName() ) );
+ }
+ }
+
+ public void testIndexAndPurge() throws Exception {
+ assertEquals(
+ "wrong even type", "manual", mbeanServer.getAttribute(
configBeanObjectName, "IndexingStrategy" )
+ );
+
+ FullTextSession s = Search.getFullTextSession( openSession() );
+ Transaction tx = s.beginTransaction();
+ Counter counter = new Counter();
+ s.save( counter );
+ tx.commit();
+ s.close();
+
+ assertNumberOfIndexedEntities( Counter.class.getName(), 0 ); // manual indexing!
+
+ mbeanServer.invoke(
+ indexBeanObjectName,
+ "index",
+ new String[] { Counter.class.getName() },
+ new String[] { String.class.getName() }
+ );
+
+ assertNumberOfIndexedEntities( Counter.class.getName(), 1 );
+
+ mbeanServer.invoke(
+ indexBeanObjectName,
+ "purge",
+ new String[] { Counter.class.getName() },
+ new String[] { String.class.getName() }
+ );
+
+ assertNumberOfIndexedEntities( Counter.class.getName(), 0 );
+ }
+
+ protected void setUp() throws Exception {
+ super.setUp();
+ mbeanServer = ManagementFactory.getPlatformMBeanServer();
+ configBeanObjectName = new ObjectName(
HibernateSearchConfigInfoMBean.CONFIG_MBEAN_OBJECT_NAME );
+ indexBeanObjectName = new ObjectName(
HibernateSearchIndexCtrlMBean.INDEX_CTRL_MBEAN_OBJECT_NAME );
+ }
+
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ if ( mbeanServer.isRegistered( configBeanObjectName ) ) {
+ mbeanServer.unregisterMBean( configBeanObjectName );
+ }
+ if ( mbeanServer.isRegistered( indexBeanObjectName ) ) {
+ mbeanServer.unregisterMBean( indexBeanObjectName );
+ }
+ }
+
+ protected void configure(Configuration cfg) {
+ super.configure( cfg );
+ File targetDir = getTargetDir();
+ File simpleJndiDir = new File( targetDir, "simpleJndi" );
+ simpleJndiDir.mkdir();
+
+ cfg.setProperty( "hibernate.session_factory_name",
"java:comp/SessionFactory" );
+ cfg.setProperty( "hibernate.jndi.class",
"org.osjava.sj.SimpleContextFactory" );
+ cfg.setProperty( "hibernate.jndi.org.osjava.sj.root",
simpleJndiDir.getAbsolutePath() );
+ cfg.setProperty( "hibernate.jndi.org.osjava.sj.jndi.shared", "true"
);
+
+ cfg.setProperty( "hibernate.search.indexing_strategy", "manual" );
+ cfg.setProperty( Environment.JMX_ENABLED, "true" );
+ }
+
+ @Override
+ protected Class<?>[] getMappings() {
+ return new Class<?>[] { Counter.class };
+ }
+
+ private void assertNumberOfIndexedEntities(String entity, int count)
+ throws InstanceNotFoundException, MBeanException, ReflectionException {
+ assertEquals(
+ "wrong number of indexed entities", count,
+ mbeanServer.invoke(
+ configBeanObjectName,
+ "getNumberOfIndexedEntities",
+ new String[] { entity },
+ new String[] { String.class.getName() }
+ )
+ );
+ }
+}
\ No newline at end of file
Added:
search/trunk/hibernate-search/src/test/java/org/hibernate/search/test/jmx/NoMBeansEnabledTest.java
===================================================================
---
search/trunk/hibernate-search/src/test/java/org/hibernate/search/test/jmx/NoMBeansEnabledTest.java
(rev 0)
+++
search/trunk/hibernate-search/src/test/java/org/hibernate/search/test/jmx/NoMBeansEnabledTest.java 2010-07-05
14:46:01 UTC (rev 19897)
@@ -0,0 +1,75 @@
+/*
+ * 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.test.jmx;
+
+import java.io.File;
+import java.lang.management.ManagementFactory;
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+
+import org.hibernate.cfg.Configuration;
+import org.hibernate.search.Environment;
+import org.hibernate.search.jmx.HibernateSearchConfigInfoMBean;
+import org.hibernate.search.jmx.HibernateSearchIndexCtrlMBean;
+import org.hibernate.search.test.SearchTestCase;
+
+/**
+ * @author Hardy Ferentschik
+ */
+public class NoMBeansEnabledTest extends SearchTestCase {
+
+ public void testMBeanNotRegisteredWithoutExplicitProperty() throws Exception {
+ MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
+
+ ObjectName name = new ObjectName(
HibernateSearchConfigInfoMBean.CONFIG_MBEAN_OBJECT_NAME );
+ assertFalse(
+ "Without '" + Environment.JMX_ENABLED + "' set the
configuration info MBean should not be registered",
+ mbs.isRegistered( name )
+ );
+
+ name = new ObjectName( HibernateSearchIndexCtrlMBean.INDEX_CTRL_MBEAN_OBJECT_NAME );
+ assertFalse(
+ "Without '" + Environment.JMX_ENABLED + "' set the index
control MBean should not be registered",
+ mbs.isRegistered( name )
+ );
+ }
+
+
+ protected void configure(Configuration cfg) {
+ super.configure( cfg );
+ File targetDir = getTargetDir();
+ File simpleJndiDir = new File( targetDir, "simpleJndi" );
+ simpleJndiDir.mkdir();
+
+ cfg.setProperty( "hibernate.session_factory_name",
"java:comp/SessionFactory" );
+ cfg.setProperty( "hibernate.jndi.class",
"org.osjava.sj.SimpleContextFactory" );
+ cfg.setProperty( "hibernate.jndi.org.osjava.sj.root",
simpleJndiDir.getAbsolutePath() );
+ cfg.setProperty( "hibernate.jndi.org.osjava.sj.jndi.shared", "true"
);
+ }
+
+ @Override
+ protected Class<?>[] getMappings() {
+ return new Class<?>[] { Counter.class };
+ }
+}
\ No newline at end of file
Deleted: search/trunk/hibernate-search/src/test/resources/jndi.properties
===================================================================
--- search/trunk/hibernate-search/src/test/resources/jndi.properties 2010-07-05 14:30:38
UTC (rev 19896)
+++ search/trunk/hibernate-search/src/test/resources/jndi.properties 2010-07-05 14:46:01
UTC (rev 19897)
@@ -1,12 +0,0 @@
-java.naming.factory.initial=org.apache.activemq.jndi.ActiveMQInitialContextFactory
-java.naming.provider.url=vm://localhost
-
-# use the following property to specify the JNDI name the connection factory
-# should appear as.
-connectionFactoryNames = ConnectionFactory, java:/ConnectionFactory
-
-# register some queues in JNDI using the form
-# queue.[jndiName] = [physicalName]
-queue.queue/searchtest = searchQueue
-
-
Modified:
search/trunk/hibernate-search-testing/src/main/java/org/hibernate/search/test/SearchTestCase.java
===================================================================
---
search/trunk/hibernate-search-testing/src/main/java/org/hibernate/search/test/SearchTestCase.java 2010-07-05
14:30:38 UTC (rev 19896)
+++
search/trunk/hibernate-search-testing/src/main/java/org/hibernate/search/test/SearchTestCase.java 2010-07-05
14:46:01 UTC (rev 19897)
@@ -26,6 +26,7 @@
import java.io.File;
import java.io.InputStream;
+import java.net.URL;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.KeywordAnalyzer;
@@ -61,14 +62,14 @@
public abstract class SearchTestCase extends TestCase {
private static final Logger log = org.hibernate.search.util.LoggerFactory.make();
-
+
public static Analyzer standardAnalyzer = new StandardAnalyzer( getTargetLuceneVersion()
);
public static Analyzer stopAnalyzer = new StopAnalyzer( getTargetLuceneVersion() );
public static Analyzer simpleAnalyzer = new SimpleAnalyzer();
public static Analyzer keywordAnalyzer = new KeywordAnalyzer();
private static File indexDir;
-
+
private SearchFactory searchFactory;
static {
@@ -129,7 +130,7 @@
tx.commit();
s.close();
}
-
+
protected SearchFactory getSearchFactory() {
if ( searchFactory == null ) {
Session session = openSession();
@@ -190,9 +191,29 @@
protected static File getIndexDir() {
return indexDir;
}
-
+
public static Version getTargetLuceneVersion() {
return Version.LUCENE_29;
}
-
+
+ /**
+ * Returns the target directory of the build.
+ *
+ * @return the target directory of the build
+ */
+ public File getTargetDir() {
+ ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
+ // get a URL reference to something we now is part of the classpath (us)
+ URL myUrl = contextClassLoader.getResource( SearchTestCase.class.getName().replace(
'.', '/' ) + ".class" );
+ File myPath = new File( myUrl.getFile() );
+ // navigate back to '/target'
+ return myPath
+ .getParentFile() // target/classes/org/hibernate/search/test
+ .getParentFile() // target/classes/org/hibernate/search
+ .getParentFile() // target/classes/org/hibernate/
+ .getParentFile() // target/classes/org
+ .getParentFile() // target/classes/
+ .getParentFile(); // target
+ }
+
}