├── .gitignore
├── pom.xml
└── src
├── main
└── java
│ └── fr
│ └── pilato
│ └── hibernate
│ └── plugins
│ └── elasticsearch
│ ├── ElasticSearchEventListener.java
│ ├── ElasticSearchEventListenerFactory.java
│ ├── ElasticSearchHelper.java
│ ├── ElasticSearchHibernateAnnotationIntrospector.java
│ ├── ElasticSearchJacksonHibernateModule.java
│ └── annotations
│ ├── ESAnalyzer.java
│ └── ESIndexed.java
└── test
├── java
└── fr
│ └── pilato
│ └── hibernate
│ └── plugins
│ └── elasticsearch
│ ├── HibernateTestCase.java
│ ├── JSonBuilderTest.java
│ └── testcase1
│ ├── ChildEntity.java
│ ├── EntityMaker.java
│ └── SimpleEntity.java
└── resources
├── log4j.xml
└── myconfig
└── myelasticsearch.yml
/.gitignore:
--------------------------------------------------------------------------------
1 | /target
2 | .classpath
3 | .settings
4 | .project
5 |
6 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
3 | 4.0.0
4 | fr.pilato.hibernate.plugins
5 | es-hibernate-connector
6 | 0.0.1-SNAPSHOT
7 | jar
8 | Hibernate to ElasticSearch Connector
9 | Make your Hibernate Search more Elastic !
10 |
11 | https://github.com/dadoonet/es-hibernate-connector/wiki
12 |
13 |
14 |
15 | The Apache Software License, Version 2.0
16 | http://www.apache.org/licenses/LICENSE-2.0.txt
17 | repo
18 |
19 |
20 |
21 |
22 | git://github.com/dadoonet/es-hibernate-connector.git
23 | git@github.com:dadoonet/es-hibernate-connector.git
24 | https://github.com/dadoonet/es-hibernate-connector
25 |
26 |
27 | 2011
28 |
29 |
30 | dadoonet
31 | David Pilato
32 | david+github@pilato.fr
33 |
34 |
35 |
36 |
37 | 0.16.0
38 | 3.6.1.Final
39 | 1.8.0
40 |
41 |
42 |
43 |
44 | dev-pilato-fr
45 | http://dev.david.pilato.fr/projects/es-hibernate-connector/${project.version}/
46 |
47 |
48 | sonatype-releases
49 | OSS Sonatype Releases
50 | https://oss.sonatype.org/content/repositories/releases/
51 |
52 |
53 | sonatype-snapshots
54 | OSS Sonatype Snapshots
55 | https://oss.sonatype.org/content/repositories/snapshots/
56 |
57 |
58 |
59 |
60 | github
61 | https://github.com/dadoonet/es-hibernate-connector/issues/
62 |
63 |
64 |
65 |
66 |
67 |
68 | maven-help-plugin
69 | 2.1.1
70 |
71 |
72 | maven-antrun-plugin
73 | 1.6
74 |
75 |
76 | maven-changes-plugin
77 | 2.4
78 |
79 |
80 | maven-project-info-reports-plugin
81 | 2.3.1
82 |
83 |
84 | maven-assembly-plugin
85 | 2.2.1
86 |
87 |
88 | maven-clean-plugin
89 | 2.4.1
90 |
91 |
92 | maven-compiler-plugin
93 | 2.3.2
94 |
95 | true
96 | true
97 | 1.6
98 | 1.6
99 |
100 |
101 |
102 | maven-dependency-plugin
103 | 2.2
104 |
105 |
106 | maven-deploy-plugin
107 | 2.5
108 |
109 |
110 | maven-ear-plugin
111 | 2.5
112 |
113 |
114 | maven-ejb-plugin
115 | 2.3
116 |
117 |
118 | maven-install-plugin
119 | 2.3.1
120 |
121 |
122 | maven-jar-plugin
123 | 2.3.1
124 |
125 |
126 | maven-plugin-plugin
127 | 2.7
128 |
129 |
130 | maven-rar-plugin
131 | 2.2
132 |
133 |
134 | maven-release-plugin
135 | 2.1
136 |
137 |
138 | maven-resources-plugin
139 | 2.5
140 |
141 |
142 | maven-site-plugin
143 | 2.2
144 |
145 |
146 | maven-pdf-plugin
147 | 1.1
148 |
149 |
150 | com.artofsolving
151 | jodconverter-maven-plugin
152 | 2.2.3
153 |
154 |
155 | maven-source-plugin
156 | 2.1.2
157 |
158 |
159 | maven-surefire-plugin
160 | 2.8
161 |
162 |
163 | maven-war-plugin
164 | 2.1.1
165 |
166 |
167 | maven-eclipse-plugin
168 | 2.8
169 |
170 |
171 | org.codehaus.mojo
172 | sonar-maven-plugin
173 | 1.0-beta-2
174 |
175 |
176 | org.apache.maven.plugins
177 | maven-enforcer-plugin
178 | 1.0
179 |
180 |
181 | validate
182 |
183 | enforce
184 |
185 |
186 |
187 |
188 | [1.6,)
189 |
190 |
191 | [2.1.0,)
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 | src/test/resources
204 | true
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 | sonatype-releases
213 | Miroir Sonatype
214 | default
215 | https://oss.sonatype.org/content/repositories/releases/
216 |
217 | false
218 |
219 |
220 |
221 | jboss-releases
222 | JBoss Repo
223 | default
224 | https://repository.jboss.org/nexus/content/groups/public/
225 |
226 | false
227 |
228 |
229 |
230 |
231 |
232 |
233 | org.elasticsearch
234 | elasticsearch
235 | ${elasticsearch.version}
236 |
237 |
238 | org.hibernate
239 | hibernate-core
240 | ${hibernate.version}
241 |
242 |
243 | org.hibernate
244 | hibernate-entitymanager
245 | ${hibernate.version}
246 |
247 |
248 | org.codehaus.jackson
249 | jackson-mapper-asl
250 | ${jackson.version}
251 |
252 |
253 | commons-logging
254 | commons-logging
255 | 1.1.1
256 |
257 |
258 | commons-beanutils
259 | commons-beanutils
260 | 1.8.3
261 |
262 |
263 | log4j
264 | log4j
265 | 1.2.13
266 | provided
267 |
268 |
269 | junit
270 | junit
271 | 4.4
272 | test
273 |
274 |
275 | org.hsqldb
276 | hsqldb
277 | 2.0.0
278 | test
279 |
280 |
281 |
282 |
--------------------------------------------------------------------------------
/src/main/java/fr/pilato/hibernate/plugins/elasticsearch/ElasticSearchEventListener.java:
--------------------------------------------------------------------------------
1 | package fr.pilato.hibernate.plugins.elasticsearch;
2 |
3 | import static org.elasticsearch.node.NodeBuilder.nodeBuilder;
4 |
5 | import java.util.HashMap;
6 | import java.util.Iterator;
7 | import java.util.Map;
8 |
9 | import javax.persistence.Id;
10 |
11 | import org.apache.commons.logging.Log;
12 | import org.apache.commons.logging.LogFactory;
13 | import org.elasticsearch.client.Client;
14 | import org.elasticsearch.node.Node;
15 | import org.elasticsearch.node.NodeBuilder;
16 | import org.hibernate.cfg.Configuration;
17 | import org.hibernate.event.Destructible;
18 | import org.hibernate.event.Initializable;
19 | import org.hibernate.event.PostDeleteEvent;
20 | import org.hibernate.event.PostDeleteEventListener;
21 | import org.hibernate.event.PostInsertEvent;
22 | import org.hibernate.event.PostInsertEventListener;
23 | import org.hibernate.event.PostUpdateEvent;
24 | import org.hibernate.event.PostUpdateEventListener;
25 | import org.hibernate.mapping.PersistentClass;
26 | import org.hibernate.util.ReflectHelper;
27 |
28 | import fr.pilato.hibernate.plugins.elasticsearch.annotations.ESIndexed;
29 |
30 | /**
31 | * ElasticSearch Hibernate Listener implementation :
32 | *
Supported Annotations (and properties) :
33 | *
34 | * - Indexed(name=)
35 | *
- Id()
36 | *
- DocumentId()
37 | *
38 | * Set es.client.only system property to false if you want to start a real node (for tests)
39 | * Use es.config system property to define your node configuration or add a config
40 | * file in the classpath
41 | * @see Indexed
42 | * @see DocumentId
43 | * @see Id
44 | * @author David Pilato
45 | */
46 | @SuppressWarnings("serial")
47 | public class ElasticSearchEventListener implements Initializable,
48 | PostDeleteEventListener,
49 | PostInsertEventListener,
50 | PostUpdateEventListener, Destructible
51 | {
52 |
53 | private static final Log log = LogFactory.getLog(ElasticSearchEventListener.class);
54 |
55 | private Node node = null;
56 |
57 | private Client client = null;
58 |
59 | private Map> entityMapper = new HashMap>();
60 |
61 | private boolean used = false;
62 |
63 | public void initialize(Configuration cfg) {
64 | // We need to configure ES to handle HSearch annotations
65 | if (log.isDebugEnabled()) log.debug( "Elastic Search Starting Configuration" );
66 |
67 | try {
68 | if (log.isDebugEnabled()) log.debug( "ES Indexed classes :" );
69 | for (Iterator itMappings = cfg.getClassMappings(); itMappings.hasNext();) {
70 | PersistentClass persistentClass = itMappings.next();
71 |
72 | // Looking if the Entity is Indexed
73 | Class> clazz = ReflectHelper.classForName( persistentClass.getEntityName() );
74 | boolean isIndexed = isEntityIndexed(clazz);
75 |
76 | if (isIndexed) {
77 | used = true;
78 | log.debug(" + " + clazz.getSimpleName());
79 | registerEntityHolder(clazz);
80 | }
81 | }
82 | } catch (ClassNotFoundException e) {
83 | // It should not be possible to get here !
84 | log.warn( "Can not find Entity Class : " + e.getMessage() );
85 | }
86 |
87 | if (log.isDebugEnabled()) log.debug( "Elastic Search Event Listener " + (used ? "activated" : "deactivated") );
88 | }
89 |
90 | /**
91 | * Starting cluster connexion
92 | */
93 | public ElasticSearchEventListener() {
94 | log.info( "Starting Elastic Search Plugin..." );
95 | boolean isClientOnly = true;
96 |
97 | // Let's find in system properties if we must start the client
98 | // as a Node also (for testing purpose)
99 | String strIsClientOnly = System.getProperty("es.client.only");
100 | if (strIsClientOnly != null && strIsClientOnly.toLowerCase().equals("false")) isClientOnly = false;
101 |
102 | log.info( "Starting Node " + (isClientOnly ? "(Client Only)" : "(Full)") + " for Elastic Search..." );
103 |
104 | NodeBuilder nodeBuilder = nodeBuilder().client(isClientOnly);
105 | node = nodeBuilder.node();
106 | client = node.client();
107 |
108 | log.info( "Node [" + node.settings().get("name") + "] for [" + node.settings().get("cluster.name") + "] cluster started..." );
109 | log.info( " - data : " + node.settings().get("path.data") );
110 | log.info( " - logs : " + node.settings().get("path.logs") );
111 | }
112 |
113 | public boolean isUsed() {
114 | return used;
115 | }
116 |
117 | public void onPostDelete(PostDeleteEvent event) {
118 | final Object entity = event.getEntity();
119 | if (isEntityIndexed(entity)) {
120 | if (log.isDebugEnabled()) log.debug("Processing Delete event on " + getEntityName(entity));
121 | ElasticSearchHelper.removeElastic(client, entity);
122 | }
123 | }
124 |
125 | public void onPostInsert(PostInsertEvent event) {
126 | final Object entity = event.getEntity();
127 | if (isEntityIndexed(entity)) {
128 | if (log.isDebugEnabled()) log.debug("Processing Insert event on " + getEntityName(entity));
129 | ElasticSearchHelper.pushElastic(client, entity);
130 | }
131 | }
132 |
133 | public void onPostUpdate(PostUpdateEvent event) {
134 | final Object entity = event.getEntity();
135 | if (isEntityIndexed(entity)) {
136 | if (log.isDebugEnabled()) log.debug("Processing Insert event on " + getEntityName(entity));
137 | ElasticSearchHelper.pushElastic(client, entity);
138 | }
139 | }
140 |
141 | private void registerEntityHolder(Class> clazz) {
142 | entityMapper.put(clazz.getName(), clazz);
143 | }
144 |
145 | private boolean isEntityIndexed(final Object entity) {
146 | // Can we find the class for this entity in ou Map ?
147 | if (entity == null) return false;
148 | String className = entity.getClass().getName();
149 |
150 | return entityMapper.containsKey(className);
151 | }
152 |
153 | /**
154 | * Find if the Entity Class is Indexed
155 | * @param clazz
156 | * @return true if true ( ;-) )
157 | */
158 | private boolean isEntityIndexed(Class> clazz) {
159 | ESIndexed annotation = (ESIndexed) clazz.getAnnotation(ESIndexed.class);
160 | if (annotation != null) {
161 | return true;
162 | }
163 | return false;
164 | }
165 |
166 | private String getEntityName(Object entity) {
167 | if (entity == null) return null;
168 | return entity.getClass().getSimpleName();
169 | }
170 |
171 | public void cleanup() {
172 | log.info("Closing Elastic Search Plugin...");
173 | if (client != null) client.close();
174 | if (node != null) node.close();
175 | }
176 |
177 | /**
178 | * Get the Elastic Search current node.
179 | *
If you only need a client, please use {@link #getESClient()} as
180 | * it will managed automatically by es-hb-connector.
181 | * @return Current ES node
182 | */
183 | public Node getESNode() {
184 | return node;
185 | }
186 |
187 | /**
188 | * Get the Elastic Search current client
189 | * @return an ES client
190 | */
191 | public Client getESClient() {
192 | return node.client();
193 | }
194 | }
195 |
--------------------------------------------------------------------------------
/src/main/java/fr/pilato/hibernate/plugins/elasticsearch/ElasticSearchEventListenerFactory.java:
--------------------------------------------------------------------------------
1 | package fr.pilato.hibernate.plugins.elasticsearch;
2 |
3 | import org.apache.commons.logging.Log;
4 | import org.apache.commons.logging.LogFactory;
5 | import org.hibernate.cfg.Configuration;
6 | import org.hibernate.event.Destructible;
7 | import org.hibernate.event.Initializable;
8 | import org.hibernate.event.PostDeleteEvent;
9 | import org.hibernate.event.PostDeleteEventListener;
10 | import org.hibernate.event.PostInsertEvent;
11 | import org.hibernate.event.PostInsertEventListener;
12 | import org.hibernate.event.PostUpdateEvent;
13 | import org.hibernate.event.PostUpdateEventListener;
14 |
15 | /**
16 | * ElasticSearch Hibernate Listener implementation
17 | * You can configure elasticSearch by specifying es.config file.
18 | * @author David Pilato
19 | */
20 | @SuppressWarnings("serial")
21 | public class ElasticSearchEventListenerFactory implements
22 | PostDeleteEventListener,
23 | PostInsertEventListener,
24 | PostUpdateEventListener,
25 | Initializable,
26 | Destructible {
27 |
28 | private static final Log log = LogFactory.getLog(ElasticSearchEventListenerFactory.class);
29 |
30 | private static ElasticSearchEventListener listener;
31 |
32 | public static ElasticSearchEventListener getInstance() {
33 | if (listener == null) {
34 | listener = new ElasticSearchEventListener();
35 | }
36 |
37 | return listener;
38 | }
39 |
40 | public void initialize(Configuration cfg) {
41 | // The first time we get here, listener is null !
42 | if (listener == null) {
43 | getInstance().initialize(cfg);
44 | }
45 | }
46 |
47 | public void onPostDelete(PostDeleteEvent event) {
48 | getInstance();
49 | if ( listener.isUsed() ) listener.onPostDelete(event);
50 | }
51 |
52 | public void onPostInsert(PostInsertEvent event) {
53 | getInstance();
54 | if ( listener.isUsed() ) listener.onPostInsert(event);
55 | }
56 |
57 | public void onPostUpdate(PostUpdateEvent event) {
58 | getInstance();
59 | if ( listener.isUsed() ) listener.onPostUpdate(event);
60 | }
61 |
62 | public void cleanup() {
63 | if (listener != null) {
64 | if (log.isDebugEnabled()) log.debug("Stopping Elastic Search Event Listener");
65 | listener.cleanup();
66 | listener = null;
67 | }
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/src/main/java/fr/pilato/hibernate/plugins/elasticsearch/ElasticSearchHelper.java:
--------------------------------------------------------------------------------
1 | package fr.pilato.hibernate.plugins.elasticsearch;
2 |
3 | import java.lang.annotation.Annotation;
4 | import java.lang.reflect.Field;
5 |
6 | import javax.persistence.Id;
7 |
8 | import org.apache.commons.beanutils.PropertyUtils;
9 | import org.apache.commons.logging.Log;
10 | import org.apache.commons.logging.LogFactory;
11 | import org.codehaus.jackson.map.ObjectMapper;
12 | import org.codehaus.jackson.map.SerializationConfig;
13 | import org.elasticsearch.action.delete.DeleteResponse;
14 | import org.elasticsearch.action.index.IndexResponse;
15 | import org.elasticsearch.client.Client;
16 |
17 | import fr.pilato.hibernate.plugins.elasticsearch.annotations.ESIndexed;
18 |
19 | /**
20 | * ElasticSearch Hibernate Listener implementation :
21 | * Supported Annotations (and properties) :
22 | *
23 | * - ESIndexed(indexName=)
24 | *
25 | *
26 | * @see ESIndexed
27 | * @author David Pilato
28 | */
29 | public class ElasticSearchHelper {
30 |
31 | private static final Log log = LogFactory.getLog(ElasticSearchHelper.class);
32 |
33 | /**
34 | * Push an entity to Elastic
35 | * @param client Elastic Search Client
36 | * @param entity Entity to remove
37 | */
38 | public static void pushElastic(Client client, Object entity) {
39 | if (entity == null)
40 | throw new RuntimeException(
41 | "Trying to index a null entity ? What a strange idea !");
42 | if (client == null) {
43 | log.error("Trying to push index to a non existing client ? Bad idea !");
44 | return;
45 | }
46 |
47 | String indexName = getEntityIndexName(entity);
48 | String entityName = getEntityName(entity);
49 | String documentId = getDocumentId(entity);
50 |
51 | if (log.isDebugEnabled())
52 | log.debug("Trying to prepare EntityBuilder for " + indexName + "/"
53 | + entityName + "/" + documentId);
54 |
55 | ObjectMapper mapper = new ObjectMapper();
56 |
57 | mapper.registerModule(new ElasticSearchJacksonHibernateModule());
58 |
59 | mapper.configure(SerializationConfig.Feature.WRITE_DATES_AS_TIMESTAMPS, true);
60 | mapper.configure(SerializationConfig.Feature.AUTO_DETECT_FIELDS, true);
61 | mapper.configure(SerializationConfig.Feature.AUTO_DETECT_GETTERS, false);
62 | mapper.configure(SerializationConfig.Feature.AUTO_DETECT_IS_GETTERS, false);
63 | mapper.configure(SerializationConfig.Feature.INDENT_OUTPUT, false);
64 |
65 | try {
66 | String result = mapper.writeValueAsString(entity);
67 | if (log.isDebugEnabled())
68 | log.debug(" - Entity will be indexed as "
69 | + result);
70 |
71 | IndexResponse response = client
72 | .prepareIndex(indexName, entityName, documentId)
73 | .setSource(result).execute().actionGet();
74 |
75 | if (log.isDebugEnabled() && response != null)
76 | log.debug(" - Entity succesfully indexed...");
77 | if (response == null)
78 | log.warn("Unable to index entity " + entityName + " : " + entity);
79 | } catch (Exception e) {
80 | log.warn("Unable to push entity into Elastic Search...");
81 | }
82 | }
83 |
84 | /**
85 | * Remove an entity from Elastic
86 | * @param client Elastic Search Client
87 | * @param entity Entity to remove
88 | */
89 | public static void removeElastic(Client client, Object entity) {
90 | if (entity == null)
91 | throw new RuntimeException(
92 | "Trying to remove a null entity ? What a strange idea !");
93 | if (client == null) {
94 | log.error("Trying to remove an index to a non existing client ? Bad idea !");
95 | return;
96 | }
97 |
98 | String indexName = getEntityIndexName(entity);
99 | String entityName = getEntityName(entity);
100 | String documentId = getDocumentId(entity);
101 |
102 | if (log.isDebugEnabled())
103 | log.debug("Trying to remove entity " + indexName + "/" + entityName
104 | + "/" + documentId);
105 | DeleteResponse response = client
106 | .prepareDelete(indexName, entityName, documentId).execute()
107 | .actionGet();
108 |
109 | // Just for debugging purpose
110 | if (log.isDebugEnabled() && response != null) {
111 | if (response.isNotFound())
112 | log.debug(" - Entity was not found...");
113 | else
114 | log.debug(" - Entity successfully removed...");
115 | }
116 | if (response == null)
117 | log.warn("Unable to remove entity " + entityName + " : " + entity);
118 | }
119 |
120 | private static Object getMemberValue(Object bean, String field) {
121 | Object value;
122 | try {
123 | value = PropertyUtils.getNestedProperty(bean, field);
124 | } catch (Exception e) {
125 | throw new IllegalStateException("Could not get property value", e);
126 | }
127 | return value;
128 | }
129 |
130 | /**
131 | * Shortcut to entity.getClass().getSimpleName()
132 | * @param entity Entity
133 | * @return simple Name for entity class
134 | */
135 | private static String getEntityName(Object entity) {
136 | if (entity == null)
137 | return null;
138 | return entity.getClass().getSimpleName();
139 | }
140 |
141 | /**
142 | * Get the index name as it was declared in ESIndexed annotation
143 | * for a given entity
144 | * @param entity Entity where to find index name
145 | * @return The index name
146 | */
147 | private static String getEntityIndexName(Object entity) {
148 | Class> clazz = entity.getClass();
149 | ESIndexed annotation = clazz.getAnnotation(ESIndexed.class);
150 |
151 | if (annotation != null) {
152 | return annotation.indexName().toLowerCase();
153 | } else {
154 | // Entity not annoted ! What the hell ????
155 | throw new RuntimeException("Entity is not annoted ! " + entity);
156 | }
157 | }
158 |
159 | /**
160 | * Get the document id
161 | *
162 | * @param entity
163 | * Entity
164 | * @return
165 | */
166 | private static String getDocumentId(Object entity) {
167 | Class> clazz = entity.getClass();
168 |
169 | String anno = findIdAnnotation(clazz);
170 |
171 | if (anno == null) {
172 | // Oh oh !!!! Big trouble !
173 | throw new RuntimeException(
174 | "Cannot find any Id or DocumentId annotation for "
175 | + clazz.getName());
176 | }
177 |
178 | // Now, we need to get the value of this field
179 | Object value = getMemberValue(entity, anno);
180 |
181 | if (value == null)
182 | throw new RuntimeException(
183 | "Cannont index an entity without a correct Id");
184 |
185 | // We expect that toString() will return the Id
186 | return value.toString();
187 | }
188 |
189 | /**
190 | * Get the document id
191 | *
192 | * @param clazz
193 | * Annoted Class
194 | * @return
195 | */
196 | private static String findIdAnnotation(Class> clazz) {
197 | if (clazz == null)
198 | return null;
199 | Field[] fields = clazz.getDeclaredFields();
200 | for (int i = 0; i < fields.length; i++) {
201 | Annotation anno = (Annotation) fields[i].getAnnotation(Id.class);
202 |
203 | if (anno != null) {
204 | return fields[i].getName();
205 | }
206 | }
207 |
208 | // We will look in parent classes
209 | return findIdAnnotation(clazz.getSuperclass());
210 | }
211 |
212 | // /**
213 | // * Get all the fields annoted by Field
214 | // *
215 | // * @param clazz
216 | // * @return
217 | // */
218 | // private static Collection getAllFieldsAnnotation(Class> clazz) {
219 | // Collection returnFields = new ArrayList();
220 | // if (clazz == null)
221 | // return returnFields;
222 | // Field[] fields = clazz.getDeclaredFields();
223 | // for (int i = 0; i < fields.length; i++) {
224 | // Annotation anno = (Annotation) fields[i]
225 | // .getAnnotation(ESField.class);
226 | //
227 | // if (anno != null) {
228 | // returnFields.add(fields[i]);
229 | // }
230 | // }
231 | //
232 | // return returnFields;
233 | // }
234 |
235 | // /**
236 | // * Get all the fields annoted by Field even in Parents !
237 | // *
238 | // * @param clazz
239 | // * @return
240 | // */
241 | // private static Collection getAllFieldsAnnotationRecursive(
242 | // Class> clazz) {
243 | // Collection returnFields = new ArrayList();
244 | // returnFields.addAll(getAllFieldsAnnotation(clazz));
245 | // if (clazz != null)
246 | // returnFields.addAll(getAllFieldsAnnotationRecursive(clazz
247 | // .getSuperclass()));
248 | // return returnFields;
249 | // }
250 |
251 | }
252 |
--------------------------------------------------------------------------------
/src/main/java/fr/pilato/hibernate/plugins/elasticsearch/ElasticSearchHibernateAnnotationIntrospector.java:
--------------------------------------------------------------------------------
1 | package fr.pilato.hibernate.plugins.elasticsearch;
2 |
3 | import org.codehaus.jackson.map.introspect.JacksonAnnotationIntrospector;
4 |
5 | // TODO for future use only
6 | public class ElasticSearchHibernateAnnotationIntrospector extends JacksonAnnotationIntrospector {
7 | }
8 |
--------------------------------------------------------------------------------
/src/main/java/fr/pilato/hibernate/plugins/elasticsearch/ElasticSearchJacksonHibernateModule.java:
--------------------------------------------------------------------------------
1 | package fr.pilato.hibernate.plugins.elasticsearch;
2 |
3 | import org.codehaus.jackson.Version;
4 | import org.codehaus.jackson.map.Module;
5 |
6 | //TODO for future use only
7 | public class ElasticSearchJacksonHibernateModule extends Module {
8 | private final String NAME = "ESJacksonHibernateModule";
9 |
10 | private final static Version VERSION = new Version(0, 1, 0, null);
11 |
12 | @Override
13 | public String getModuleName() {
14 | return NAME;
15 | }
16 |
17 | @Override
18 | public Version version() {
19 | return VERSION;
20 | }
21 |
22 | @Override
23 | public void setupModule(SetupContext context) {
24 | context.insertAnnotationIntrospector(new ElasticSearchHibernateAnnotationIntrospector());
25 | // context.addSerializers(...);
26 | }
27 | }
--------------------------------------------------------------------------------
/src/main/java/fr/pilato/hibernate/plugins/elasticsearch/annotations/ESAnalyzer.java:
--------------------------------------------------------------------------------
1 | package fr.pilato.hibernate.plugins.elasticsearch.annotations;
2 |
3 | import java.lang.annotation.Documented;
4 | import java.lang.annotation.ElementType;
5 | import java.lang.annotation.Retention;
6 | import java.lang.annotation.RetentionPolicy;
7 | import java.lang.annotation.Target;
8 |
9 | /**
10 | * Indicate the analyze for field or method (default : "default")
11 | * E.g. : ESAnalyzer(analyzer="french")
12 | *
See Elastic Search Guide
13 | * @deprecated by Annotations from OSEM Elastic Annotations
14 | * @author David Pilato
15 | */
16 | @Retention( RetentionPolicy.RUNTIME )
17 | @Target( {ElementType.FIELD, ElementType.METHOD} )
18 | @Documented
19 | @Deprecated
20 | public @interface ESAnalyzer {
21 | /**
22 | * @return the analyzer used by Elastic (Default : "default")
23 | */
24 | String analyzer() default "default";
25 | }
26 |
--------------------------------------------------------------------------------
/src/main/java/fr/pilato/hibernate/plugins/elasticsearch/annotations/ESIndexed.java:
--------------------------------------------------------------------------------
1 | package fr.pilato.hibernate.plugins.elasticsearch.annotations;
2 |
3 | import java.lang.annotation.Documented;
4 | import java.lang.annotation.ElementType;
5 | import java.lang.annotation.Retention;
6 | import java.lang.annotation.RetentionPolicy;
7 | import java.lang.annotation.Target;
8 |
9 | /**
10 | * Indicate that the entity will be indexed by Elastic Search
11 | * @deprecated by Annotations from OSEM Elastic Annotations
12 | * @author David Pilato
13 | */
14 | @Retention( RetentionPolicy.RUNTIME )
15 | @Target( ElementType.TYPE )
16 | @Documented
17 | @Deprecated
18 | public @interface ESIndexed {
19 | /**
20 | * @return the index Name used by Elastic (Default : "default")
21 | */
22 | String indexName() default "default";
23 | }
24 |
--------------------------------------------------------------------------------
/src/test/java/fr/pilato/hibernate/plugins/elasticsearch/HibernateTestCase.java:
--------------------------------------------------------------------------------
1 | package fr.pilato.hibernate.plugins.elasticsearch;
2 |
3 | import static org.elasticsearch.index.query.xcontent.QueryBuilders.termQuery;
4 | import static org.elasticsearch.node.NodeBuilder.nodeBuilder;
5 | import static org.junit.Assert.assertEquals;
6 | import static org.junit.Assert.fail;
7 |
8 | import java.io.File;
9 | import java.net.URL;
10 |
11 | import org.elasticsearch.action.count.CountResponse;
12 | import org.elasticsearch.action.search.SearchResponse;
13 | import org.elasticsearch.action.search.SearchType;
14 | import org.elasticsearch.client.Client;
15 | import org.elasticsearch.node.Node;
16 | import org.hibernate.Session;
17 | import org.hibernate.SessionFactory;
18 | import org.hibernate.Transaction;
19 | import org.hibernate.cfg.Configuration;
20 | import org.hibernate.tool.hbm2ddl.SchemaExport;
21 | import org.junit.AfterClass;
22 | import org.junit.BeforeClass;
23 | import org.junit.Test;
24 |
25 | import fr.pilato.hibernate.plugins.elasticsearch.testcase1.ChildEntity;
26 | import fr.pilato.hibernate.plugins.elasticsearch.testcase1.EntityMaker;
27 | import fr.pilato.hibernate.plugins.elasticsearch.testcase1.SimpleEntity;
28 |
29 | public class HibernateTestCase {
30 |
31 | protected static Configuration cfg;
32 | protected static Session session;
33 | protected static Node node;
34 | protected static Client client;
35 |
36 | private static boolean deleteDirectory(File path) {
37 | if( path.exists() ) {
38 | File[] files = path.listFiles();
39 | for(int i=0; i settings = node.settings().getAsMap();
66 | //
67 | // for (String string : settings.keySet()) {
68 | // System.out.println(string + " : " + settings.get(string));
69 | // }
70 |
71 | // Removing old test files
72 | // We ask to the node where are datas
73 | String dataDir = node.settings().get("path.data");
74 | HibernateTestCase.deleteDirectory( new File(dataDir) );
75 |
76 | // Setting things for Hibernate
77 | if (cfg == null) {
78 | cfg = new Configuration();
79 | cfg.setProperty(org.hibernate.cfg.Environment.SHOW_SQL, "true");
80 | cfg.setProperty(org.hibernate.cfg.Environment.HBM2DDL_AUTO, "create");
81 | cfg.setProperty(org.hibernate.cfg.Environment.DIALECT, "org.hibernate.dialect.HSQLDialect");
82 | cfg.setProperty(org.hibernate.cfg.Environment.DRIVER, "org.hsqldb.jdbcDriver");
83 | cfg.setProperty(org.hibernate.cfg.Environment.URL, "jdbc:hsqldb:mem:aname");
84 | cfg.setProperty(org.hibernate.cfg.Environment.USER, "sa");
85 | cfg.setProperty(org.hibernate.cfg.Environment.PASS, "");
86 | cfg.addAnnotatedClass(SimpleEntity.class);
87 | cfg.addAnnotatedClass(ChildEntity.class);
88 |
89 | // Activate automatic indexing with ES
90 | cfg.setProperty("hibernate.search.autoregister_listeners", "false");
91 | cfg.setListener("post-delete", "fr.pilato.hibernate.plugins.elasticsearch.ElasticSearchEventListenerFactory");
92 | cfg.setListener("post-update", "fr.pilato.hibernate.plugins.elasticsearch.ElasticSearchEventListenerFactory");
93 | cfg.setListener("post-insert", "fr.pilato.hibernate.plugins.elasticsearch.ElasticSearchEventListenerFactory");
94 |
95 | SessionFactory sf = cfg.buildSessionFactory();
96 | session = sf.openSession();
97 | SchemaExport export = new SchemaExport( cfg );
98 | export.create( true, true );
99 | }
100 |
101 | SimpleEntity entity = EntityMaker.getEntity4_2();
102 |
103 | Transaction tx = null;
104 | try {
105 | tx = session.beginTransaction();
106 |
107 | session.persist(entity);
108 |
109 | tx.commit();
110 | }
111 | catch (Exception e) {
112 | if (tx != null) tx.rollback();
113 | fail("Cannot persist entity before running the real Elastic Test : " + e.getMessage());
114 | }
115 |
116 | node = node.start();
117 | client = node.client();
118 |
119 | // Just wait a while for synchronizing the two nodes (HibernateNode and JUnitTestNode)
120 | Thread.sleep(1000);
121 | }
122 |
123 | @AfterClass
124 | public static void tearDown() throws Exception {
125 | if (client != null) {
126 | client.close();
127 | }
128 | if (node != null) {
129 | node.close();
130 | }
131 |
132 | if (session != null) {
133 | session.getSessionFactory().close();
134 | session.close();
135 | }
136 | }
137 |
138 | @Test
139 | public void countEntity() {
140 | CountResponse response = client.prepareCount("default")
141 | .setQuery(termQuery("value", "child"))
142 | .execute()
143 | .actionGet();
144 |
145 | assertEquals("We should find one document with this criteria", 1, response.count());
146 | }
147 |
148 | @Test
149 | public void findEntity() {
150 | SearchResponse response = client.prepareSearch("default")
151 | .setSearchType(SearchType.DFS_QUERY_THEN_FETCH)
152 | .setQuery(termQuery("value", "child"))
153 | .setFrom(0).setSize(60).setExplain(true)
154 | .execute()
155 | .actionGet();
156 |
157 | assertEquals("We should find one document with this criteria", 1, response.getHits().getTotalHits());
158 | }
159 |
160 | @Test
161 | public void doNotFindEntity() {
162 | SearchResponse response = client.prepareSearch("default")
163 | .setSearchType(SearchType.DFS_QUERY_THEN_FETCH)
164 | .setQuery(termQuery("value", "djsfhdhfhifhize"))
165 | .setFrom(0).setSize(60).setExplain(true)
166 | .execute()
167 | .actionGet();
168 |
169 | assertEquals("We should find nothing with this criteria", 0, response.getHits().getTotalHits());
170 | }
171 | }
172 |
--------------------------------------------------------------------------------
/src/test/java/fr/pilato/hibernate/plugins/elasticsearch/JSonBuilderTest.java:
--------------------------------------------------------------------------------
1 | package fr.pilato.hibernate.plugins.elasticsearch;
2 |
3 | import static org.junit.Assert.assertNotNull;
4 | import static org.junit.Assert.assertEquals;
5 | import static org.junit.Assert.fail;
6 |
7 | import java.io.IOException;
8 |
9 | import org.codehaus.jackson.JsonGenerationException;
10 | import org.codehaus.jackson.map.JsonMappingException;
11 | import org.codehaus.jackson.map.ObjectMapper;
12 | import org.codehaus.jackson.map.SerializationConfig;
13 | import org.junit.Test;
14 |
15 | import fr.pilato.hibernate.plugins.elasticsearch.ElasticSearchJacksonHibernateModule;
16 | import fr.pilato.hibernate.plugins.elasticsearch.testcase1.EntityMaker;
17 |
18 | /**
19 | * @author PILATO
20 | *
21 | */
22 | public class JSonBuilderTest {
23 |
24 | private String generateJsonFromEntity(Object entity, String expected) {
25 | ObjectMapper mapper = new ObjectMapper();
26 |
27 | // mapper.getSerializationConfig().setAnnotationIntrospector(new ElasticSearchHibernateAnnotationIntrospector());
28 | mapper.registerModule(new ElasticSearchJacksonHibernateModule());
29 |
30 | mapper.configure(SerializationConfig.Feature.WRITE_DATES_AS_TIMESTAMPS, false);
31 | mapper.configure(SerializationConfig.Feature.AUTO_DETECT_FIELDS, true);
32 | mapper.configure(SerializationConfig.Feature.AUTO_DETECT_GETTERS, false);
33 | mapper.configure(SerializationConfig.Feature.AUTO_DETECT_IS_GETTERS, false);
34 | mapper.configure(SerializationConfig.Feature.INDENT_OUTPUT, false);
35 |
36 | String s = null;
37 | try {
38 | s = mapper.writeValueAsString(entity);
39 | } catch (JsonGenerationException e) {
40 | fail("JsonGenerationException : " + e.getMessage());
41 | } catch (JsonMappingException e) {
42 | fail("JsonMappingException : " + e.getMessage());
43 | } catch (IOException e) {
44 | fail("IOException : " + e.getMessage());
45 | }
46 |
47 | assertNotNull(s);
48 |
49 | if (expected != null) assertEquals(expected, s);
50 |
51 | // System.out.println(s);
52 | return s;
53 | }
54 |
55 | @Test
56 | public void testModelEntity1() throws IOException {
57 | String expected = "{\"field\":null,\"sentities\":[]}";
58 | generateJsonFromEntity(EntityMaker.getEntity1(), expected);
59 | }
60 |
61 | @Test
62 | public void testModelEntity2() throws IOException {
63 | String expected = "{\"field\":\"my field 1\",\"sentities\":[]}";
64 | generateJsonFromEntity(EntityMaker.getEntity2(), expected);
65 | }
66 |
67 | @Test
68 | public void testModelEntity3_1() throws IOException {
69 | String expected = "{\"field\":\"my field 1\",\"sentities\":[{\"value\":null}]}";
70 | generateJsonFromEntity(EntityMaker.getEntity3_1(), expected);
71 | }
72 |
73 | @Test
74 | public void testModelEntity3_2() throws IOException {
75 | String expected = "{\"field\":\"my field 1\",\"sentities\":[{\"value\":\"my child 1 field\"}]}";
76 | generateJsonFromEntity(EntityMaker.getEntity3_2(), expected);
77 | }
78 |
79 | @Test
80 | public void testModelEntity4_1() throws IOException {
81 | String expected = "{\"field\":\"my field 1\",\"sentities\":[{\"value\":null},{\"value\":null}]}";
82 | generateJsonFromEntity(EntityMaker.getEntity4_1(), expected);
83 | }
84 |
85 | @Test
86 | public void testModelEntity4_2() throws IOException {
87 | String expected = "{\"field\":\"my field 1\",\"sentities\":[{\"value\":\"my child 1 field\"},{\"value\":\"my child 2 field\"}]}";
88 | generateJsonFromEntity(EntityMaker.getEntity4_2(), expected);
89 | }
90 |
91 | }
92 |
--------------------------------------------------------------------------------
/src/test/java/fr/pilato/hibernate/plugins/elasticsearch/testcase1/ChildEntity.java:
--------------------------------------------------------------------------------
1 | package fr.pilato.hibernate.plugins.elasticsearch.testcase1;
2 |
3 | import javax.persistence.Entity;
4 | import javax.persistence.GeneratedValue;
5 | import javax.persistence.Id;
6 |
7 | import org.codehaus.jackson.map.annotate.JsonSerialize;
8 |
9 | @Entity
10 | public class ChildEntity {
11 | @Id
12 | @GeneratedValue
13 | private Long id;
14 |
15 | @JsonSerialize
16 | private String value;
17 |
18 | public Long getId() {
19 | return id;
20 | }
21 |
22 | public void setId(Long id) {
23 | this.id = id;
24 | }
25 | public String getValue() {
26 | return value;
27 | }
28 |
29 | public void setValue(String value) {
30 | this.value = value;
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/test/java/fr/pilato/hibernate/plugins/elasticsearch/testcase1/EntityMaker.java:
--------------------------------------------------------------------------------
1 | package fr.pilato.hibernate.plugins.elasticsearch.testcase1;
2 |
3 | public class EntityMaker {
4 |
5 | /**
6 | * @return An empty entity
7 | */
8 | public static SimpleEntity getEntity1() {
9 | SimpleEntity entity = new SimpleEntity();
10 | return entity;
11 | }
12 |
13 | /**
14 | * @return {@link #getEntity1()} + field set to "my field 1"
15 | */
16 | public static SimpleEntity getEntity2() {
17 | SimpleEntity entity = getEntity1();
18 | entity.setField("my field 1");
19 | return entity;
20 | }
21 |
22 | /**
23 | * @return {@link #getEntity2()} + one empty child entity
24 | */
25 | public static SimpleEntity getEntity3_1() {
26 | SimpleEntity entity = getEntity2();
27 | ChildEntity centity = new ChildEntity();
28 | entity.addToSentities(centity);
29 |
30 | return entity;
31 | }
32 |
33 | /**
34 | * @return {@link #getEntity2()} + one child entity with field "my child 1 field"
35 | */
36 | public static SimpleEntity getEntity3_2() {
37 | SimpleEntity entity = getEntity2();
38 | ChildEntity centity = new ChildEntity();
39 | centity.setValue("my child 1 field");
40 | entity.addToSentities(centity);
41 |
42 | return entity;
43 | }
44 |
45 | /**
46 | * @return {@link #getEntity3_1()} + one empty child entity
47 | */
48 | public static SimpleEntity getEntity4_1() {
49 | SimpleEntity entity = getEntity3_1();
50 | ChildEntity centity = new ChildEntity();
51 | entity.addToSentities(centity);
52 |
53 | return entity;
54 | }
55 |
56 | /**
57 | * @return {@link #getEntity3_2()} + one child entity with field "my child 2 field"
58 | */
59 | public static SimpleEntity getEntity4_2() {
60 | SimpleEntity entity = getEntity3_2();
61 | ChildEntity centity = new ChildEntity();
62 | centity.setValue("my child 2 field");
63 | entity.addToSentities(centity);
64 |
65 | return entity;
66 | }
67 |
68 | }
69 |
--------------------------------------------------------------------------------
/src/test/java/fr/pilato/hibernate/plugins/elasticsearch/testcase1/SimpleEntity.java:
--------------------------------------------------------------------------------
1 | package fr.pilato.hibernate.plugins.elasticsearch.testcase1;
2 |
3 | import java.util.ArrayList;
4 | import java.util.Collection;
5 |
6 | import javax.persistence.CascadeType;
7 | import javax.persistence.Entity;
8 | import javax.persistence.GeneratedValue;
9 | import javax.persistence.Id;
10 | import javax.persistence.OneToMany;
11 | import javax.persistence.Transient;
12 |
13 | import org.codehaus.jackson.map.annotate.JsonSerialize;
14 | import org.hibernate.annotations.Cascade;
15 |
16 | import fr.pilato.hibernate.plugins.elasticsearch.annotations.ESIndexed;
17 |
18 | @Entity
19 | @ESIndexed
20 | public class SimpleEntity {
21 | @Id
22 | @GeneratedValue
23 | private Long id;
24 |
25 | @JsonSerialize
26 | private String field;
27 |
28 | // Won't be serialize so not annotated with JsonSerialize
29 | @Transient
30 | private Collection stringsfield = new ArrayList();
31 |
32 | @JsonSerialize
33 | @OneToMany( cascade = {CascadeType.PERSIST, CascadeType.MERGE} )
34 | @Cascade({org.hibernate.annotations.CascadeType.SAVE_UPDATE,
35 | org.hibernate.annotations.CascadeType.DELETE})
36 | private Collection sentities = new ArrayList();
37 |
38 | public Long getId() {
39 | return id;
40 | }
41 |
42 | public void setId(Long id) {
43 | this.id = id;
44 | }
45 |
46 | public Collection getSentities() {
47 | return sentities;
48 | }
49 |
50 | public void setSentities(Collection sentities) {
51 | this.sentities = sentities;
52 | }
53 |
54 | public void addToSentities(ChildEntity entity) {
55 | this.sentities.add(entity);
56 | }
57 |
58 | public String getField() {
59 | return field;
60 | }
61 |
62 | public void setField(String field) {
63 | this.field = field;
64 | }
65 |
66 | public Collection getStringsfield() {
67 | return stringsfield;
68 | }
69 |
70 | public void setStringsfield(Collection stringsfield) {
71 | this.stringsfield = stringsfield;
72 | }
73 |
74 | public void addToStringsfield(String string) {
75 | this.stringsfield.add(string);
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/src/test/resources/log4j.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/src/test/resources/myconfig/myelasticsearch.yml:
--------------------------------------------------------------------------------
1 | # Cluster Settings
2 | cluster:
3 | name: myTestCluster
4 |
5 | path:
6 | data: ${project.build.directory}/esdata
7 | logs: ${project.build.directory}/eslogs
8 | work: ${project.build.directory}/eswork
9 |
10 |
11 | # Gateway Settings
12 | #gateway:
13 | # recover_after_nodes: 1
14 | # recover_after_time: 5m
15 | # expected_nodes: 2
16 |
--------------------------------------------------------------------------------