/
OutboxPollingOutboxEventAdditionalJaxbMappingProducer.java
161 lines (138 loc) · 8.3 KB
/
OutboxPollingOutboxEventAdditionalJaxbMappingProducer.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
/*
* Hibernate Search, full-text search for your domain model
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.search.mapper.orm.coordination.outboxpolling.event.impl;
import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.lang.invoke.MethodHandles;
import java.util.Collection;
import java.util.Collections;
import java.util.Locale;
import java.util.Optional;
import org.hibernate.boot.jaxb.Origin;
import org.hibernate.boot.jaxb.SourceType;
import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmHibernateMapping;
import org.hibernate.boot.jaxb.internal.MappingBinder;
import org.hibernate.boot.jaxb.spi.Binding;
import org.hibernate.boot.model.source.internal.hbm.MappingDocument;
import org.hibernate.boot.spi.MetadataBuildingContext;
import org.hibernate.search.engine.cfg.ConfigurationPropertySource;
import org.hibernate.search.engine.cfg.spi.ConfigurationProperty;
import org.hibernate.search.engine.cfg.spi.OptionalConfigurationProperty;
import org.hibernate.search.mapper.orm.bootstrap.spi.HibernateSearchOrmMappingProducer;
import org.hibernate.search.mapper.orm.coordination.outboxpolling.cfg.HibernateOrmMapperOutboxPollingSettings;
import org.hibernate.search.mapper.orm.coordination.outboxpolling.cfg.spi.HibernateOrmMapperOutboxPollingSpiSettings;
import org.hibernate.search.mapper.orm.coordination.outboxpolling.cluster.impl.OutboxPollingAgentAdditionalJaxbMappingProducer;
import org.hibernate.search.mapper.orm.coordination.outboxpolling.logging.impl.Log;
import org.hibernate.search.util.common.annotation.impl.SuppressForbiddenApis;
import org.hibernate.search.util.common.logging.impl.LoggerFactory;
public final class OutboxPollingOutboxEventAdditionalJaxbMappingProducer
implements HibernateSearchOrmMappingProducer {
private static final Log log = LoggerFactory.make( Log.class, MethodHandles.lookup() );
private static final String HIBERNATE_SEARCH = OutboxPollingAgentAdditionalJaxbMappingProducer.HIBERNATE_SEARCH;
private static final String CLASS_NAME = OutboxEvent.class.getName();
// Setting both the JPA entity name and the native entity name to the FQCN so that:
// 1. We don't pollute the namespace of JPA entity names with something like
// "OutboxEvent" that could potentially conflict with user-defined entities.
// 2. We can still use session methods (persist, ...) without passing the entity name,
// because our override actually matches the default for the native entity name.
public static final String ENTITY_NAME = CLASS_NAME;
public static final String ENTITY_DEFINITION_TEMPLATE = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
"<hibernate-mapping schema=\"%1$s\" catalog=\"%2$s\">\n" +
" <class name=\"" + CLASS_NAME + "\" entity-name=\"" + ENTITY_NAME + "\" table=\"%3$s\">\n" +
" <id name=\"id\" type=\"long\">\n" +
" <generator class=\"org.hibernate.id.enhanced.SequenceStyleGenerator\">\n" +
" <param name=\"sequence_name\">%4$s</param>\n" +
" <param name=\"table_name\">%4$s</param>\n" +
" <param name=\"initial_value\">1</param>\n" +
" <param name=\"increment_size\">1</param>\n" +
" </generator>\n" +
" </id>\n" +
" <property name=\"entityName\" type=\"string\" length=\"256\" nullable=\"false\" />\n" +
" <property name=\"entityId\" type=\"string\" length=\"256\" nullable=\"false\" />\n" +
" <property name=\"entityIdHash\" type=\"integer\" index=\"entityIdHash\" nullable=\"false\" />\n" +
" <property name=\"payload\" type=\"materialized_blob\" nullable=\"false\" />\n" +
" <property name=\"retries\" type=\"integer\" nullable=\"false\" />\n" +
" <property name=\"processAfter\" type=\"instant\" index=\"processAfter\" nullable=\"true\" />\n" +
" <property name=\"status\" index=\"status\" nullable=\"false\">\n" +
" <type name=\"org.hibernate.type.EnumType\">\n" +
" <param name=\"enumClass\">" + OutboxEvent.Status.class.getName() + "</param>\n" +
" </type>\n" +
" </property>\n" +
" </class>\n" +
"</hibernate-mapping>\n";
public static final String ENTITY_DEFINITION = String.format(
Locale.ROOT, ENTITY_DEFINITION_TEMPLATE, "", "",
HibernateOrmMapperOutboxPollingSettings.Defaults.COORDINATION_ENTITY_MAPPING_OUTBOX_EVENT_TABLE,
HibernateOrmMapperOutboxPollingSettings.Defaults.COORDINATION_ENTITY_MAPPING_OUTBOX_EVENT_GENERATOR
);
private static final OptionalConfigurationProperty<String> OUTBOXEVENT_ENTITY_MAPPING =
ConfigurationProperty.forKey(
HibernateOrmMapperOutboxPollingSpiSettings.CoordinationRadicals.OUTBOXEVENT_ENTITY_MAPPING )
.asString()
.build();
private static final OptionalConfigurationProperty<String> ENTITY_MAPPING_OUTBOXEVENT_SCHEMA =
ConfigurationProperty.forKey(
HibernateOrmMapperOutboxPollingSettings.CoordinationRadicals.ENTITY_MAPPING_OUTBOXEVENT_SCHEMA )
.asString()
.build();
private static final OptionalConfigurationProperty<String> ENTITY_MAPPING_OUTBOXEVENT_CATALOG =
ConfigurationProperty.forKey(
HibernateOrmMapperOutboxPollingSettings.CoordinationRadicals.ENTITY_MAPPING_OUTBOXEVENT_CATALOG )
.asString()
.build();
private static final OptionalConfigurationProperty<String> ENTITY_MAPPING_OUTBOXEVENT_TABLE =
ConfigurationProperty.forKey(
HibernateOrmMapperOutboxPollingSettings.CoordinationRadicals.ENTITY_MAPPING_OUTBOXEVENT_TABLE )
.asString()
.build();
private static final OptionalConfigurationProperty<String> ENTITY_MAPPING_OUTBOXEVENT_GENERATOR =
ConfigurationProperty.forKey(
HibernateOrmMapperOutboxPollingSettings.CoordinationRadicals.ENTITY_MAPPING_OUTBOXEVENT_GENERATOR )
.asString()
.build();
@Override
@SuppressForbiddenApis(reason = "Strangely, this SPI involves the internal MappingBinder class,"
+ " and there's nothing we can do about it")
public Collection<MappingDocument> produceMappings(ConfigurationPropertySource propertySource,
MappingBinder mappingBinder, MetadataBuildingContext buildingContext) {
Optional<String> mapping = OUTBOXEVENT_ENTITY_MAPPING.get( propertySource );
Optional<String> schema = ENTITY_MAPPING_OUTBOXEVENT_SCHEMA.get( propertySource );
Optional<String> catalog = ENTITY_MAPPING_OUTBOXEVENT_CATALOG.get( propertySource );
Optional<String> table = ENTITY_MAPPING_OUTBOXEVENT_TABLE.get( propertySource );
Optional<String> generator = ENTITY_MAPPING_OUTBOXEVENT_GENERATOR.get( propertySource );
// only allow configuring the entire mapping or table/catalog/schema/generator names
if ( mapping.isPresent() && ( schema.isPresent() || catalog.isPresent() || table.isPresent() || generator.isPresent() ) ) {
throw log.outboxEventConfigurationPropertyConflict(
OUTBOXEVENT_ENTITY_MAPPING.resolveOrRaw( propertySource ),
new String[] {
ENTITY_MAPPING_OUTBOXEVENT_SCHEMA.resolveOrRaw( propertySource ),
ENTITY_MAPPING_OUTBOXEVENT_CATALOG.resolveOrRaw( propertySource ),
ENTITY_MAPPING_OUTBOXEVENT_TABLE.resolveOrRaw( propertySource ),
ENTITY_MAPPING_OUTBOXEVENT_GENERATOR.resolveOrRaw( propertySource )
}
);
}
String entityDefinition = mapping.orElseGet( () ->
String.format(
Locale.ROOT,
ENTITY_DEFINITION_TEMPLATE,
schema.orElse( "" ),
catalog.orElse( "" ),
table.orElse( HibernateOrmMapperOutboxPollingSettings.Defaults.COORDINATION_ENTITY_MAPPING_OUTBOX_EVENT_TABLE ),
generator.orElse( HibernateOrmMapperOutboxPollingSettings.Defaults.COORDINATION_ENTITY_MAPPING_OUTBOX_EVENT_GENERATOR )
)
);
log.outboxEventGeneratedEntityMapping( entityDefinition );
Origin origin = new Origin( SourceType.OTHER, HIBERNATE_SEARCH );
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream( entityDefinition.getBytes() );
BufferedInputStream bufferedInputStream = new BufferedInputStream( byteArrayInputStream );
Binding<?> binding = mappingBinder.bind( bufferedInputStream, origin );
JaxbHbmHibernateMapping root = (JaxbHbmHibernateMapping) binding.getRoot();
MappingDocument mappingDocument = new MappingDocument( HIBERNATE_SEARCH, root, origin, buildingContext );
return Collections.singletonList( mappingDocument );
}
}