How to make elasticsearch embedded accessible via localhost:9200 - elasticsearch

I am playing with spring-boot-sample-data-elastcisearch project.
I've changed the pom and added:
SampleElasticsearchApplicationWebXml extends SpringBootServletInitializer
to run with Tomcat embedded.
My application.properties has
spring.data.elasticsearch.http-enabled=true
spring.data.elasticsearch.local=true
I want to be able to connect to localhost:9200 in order to use elasticsearch-head or other JS client. What am I missing?
Thanks,
Milan

According to this ticket, you can now simply add this line to your configuration files:
spring.data.elasticsearch.properties.http.enabled=true

you should define this for yourself, because NodeClientFactoryBean has an option for http.enabled but ElasticSearchAutoConfiguration does not (yet) set it.
#Configuration
#EnableConfigurationProperties(ElasticsearchProperties.class)
public class ElasticsearchConfiguration implements DisposableBean {
private static Log logger = LogFactory.getLog(ElasticsearchConfiguration.class);
#Autowired
private ElasticsearchProperties properties;
private NodeClient client;
#Bean
public ElasticsearchTemplate elasticsearchTemplate() {
return new ElasticsearchTemplate(esClient());
}
#Bean
public Client esClient() {
try {
if (logger.isInfoEnabled()) {
logger.info("Starting Elasticsearch client");
}
NodeBuilder nodeBuilder = new NodeBuilder();
nodeBuilder
.clusterName(this.properties.getClusterName())
.local(false)
;
nodeBuilder.settings()
.put("http.enabled", true)
;
this.client = (NodeClient)nodeBuilder.node().client();
return this.client;
}
catch (Exception ex) {
throw new IllegalStateException(ex);
}
}
#Override
public void destroy() throws Exception {
if (this.client != null) {
try {
if (logger.isInfoEnabled()) {
logger.info("Closing Elasticsearch client");
}
if (this.client != null) {
this.client.close();
}
}
catch (final Exception ex) {
if (logger.isErrorEnabled()) {
logger.error("Error closing Elasticsearch client: ", ex);
}
}
}
}
}

Related

What would be the Alternative for SimpleNamingContextBuilder, since it is depricated?

I have a Naming Builder class which registers the objects in the JNDI directory from a map. it is recommended by Spring to replace its own deprecated JNDI Mock implementation. Deprecated as of Spring Framework 5.2 in favor of complete solutions from third parties such as Simple-JNDI
import org.springframework.mock.jndi.SimpleNamingContextBuilder;
public class SMNContextBuilder implements InitializingBean{
private Map ncMap;
public void afterPropertiesSet() throws Exception {
if (ncMap == null) {
throw new IllegalStateException("ncMap is null!");
}
SimpleNamingContextBuilder.emptyActivatedContextBuilder();
bindObjects();
}
protected void bindObjects() {
for (Iterator iter = ncMap.entrySet().iterator(); iter
.hasNext();) {
Map.Entry entryTmp = (Map.Entry) iter.next();
SimpleNamingContextBuilder.getCurrentContextBuilder().bind(
"" + entryTmp.getKey(), entryTmp.getValue());
}
}
public void setNamingContextMap(Map ncMapPar) {
ncMap = ncMapPar;
}
}
Then, I have a Test Config where this is used.
#Configuration
public class MQTestConfig {
#Bean
public SMNContextBuilder jnidInitializingBean() throws JMSException {
SMNContextBuilder builder = new SMNContextBuilder ();
Map<String, Object> map = new HashMap<>();
map.put("java:comp/env/jms/My_ConFac", myConnectionFactory());
map.put("jms/My_Queue", myQueue());
builder.setNamingContextMap(map);
return builder;
}
What would be the Alternative of using SimpleNamingContextBuilder?
I have tried the following:
import javax.naming.InitialContext;
public class SMNContextBuilder implements InitializingBean{
private Map ncMap;
InitialContext ctx;
public SimpleMapNamingContextBuilder() {
try {
this.ctx = new InitialContext();
} catch (NamingException e) {
e.printStackTrace();
}
}
public void afterPropertiesSet() throws Exception {
if (ncMap == null) {
throw new IllegalStateException("ncMap is null!");
}
SMNContextBuilder.emptyActivatedContextBuilder();
bindObjects();
}
protected void bindObjects() {
for (Iterator iter = ncMap.entrySet().iterator(); iter
.hasNext();) {
Map.Entry entryTmp = (Map.Entry) iter.next();
try {
ctx.bind(
"" + entryTmp.getKey(), entryTmp.getValue());
} catch (NamingException e) {
e.printStackTrace();
}
}
}
public void setNamingContextMap(Map ncMapPar) {
ncMap = ncMapPar;
}
}
As you point out in the question, Spring's recommendation is to use Simple-JNDI.
Combing through the documentation, it doesn't look like there is a way to easily replace a class from this library into your current code, but it appears you can still accomplish what you want by loading your beans (in this case myConnectionFactory() and myQueue() into your InitialContext using Properties. See this section of the documentation.
It does seem like the more common avenue is to configure your JNDI resources using .xml/.properties/.ini files. There is a lot of documentation on how to do this in the Simple-JNDI github page (linked above)

ControllerAdvice is not triggered in my springboot application?

Actually I am working in a Kafka streams application using Spring Boot.
So here I am trying to handle exceptions globally using #ControllerAdvice but it is not working for me.
Is it possible to use #ControllerAdvice in my application.
Is this controller advice is only works when the error is coming from controller.
Note: I am not having any controller / rest controller endpoints in my application.
Can we achieve the same in some other ways?
Please share your valuable thoughts!
Main Stream:
#Autowired
private XyzTransformer xyztransformer;
#Bean
public KStream<String, ABC> processMember(#Qualifier("defaultKafkaStreamsBuilder") StreamsBuilder streamsBuilder) {
try {
LOGGER.info("streaming started...");
KStream<String, Xyz> xyStream = streamsBuilder.stream(appProperty.kafkaStreamsTopicInput)
.transformValues(() -> xyztransformer)
xyStream.to(appProperty.kafkaStreamsTopicOutput);
return memberStream;
} catch (Exception ex) {
LOGGER.error("Exception occurred in Streams " + Arrays.toString(ex.getStackTrace()));
throw ex;
}
}
TransformerClass:
#Component
public class XyzTransformer implements ValueTransformer<Xyz, Abc> {
#Override
public void close() {
}
#Override
public void init(ProcessorContext processorContext) {
}
#SneakyThrows
#Override
public Abc transform(Xyz data) {
String[] dataSourceTables = new String[]{"abc"};
try {
return Abc.builder()
.name(data.getName())
.build();
} catch (Exception ex) {
System.out.println("catched and throwing");
throw new CustomTesException("test 1");
}
}
}
ControllerAdvice:
#ControllerAdvice
public class Advice extends ResponseEntityExceptionHandler {
#ExceptionHandler(NullPointerException.class)
public final void handleAllExceptions(NullPointerException ex) {
System.out.println("it is in the handler");
System.out.println(ex.getMessage());
}
#ExceptionHandler(Exception.class)
public final void handleAllException(Exception ex) {
System.out.println("it is in the exception handler");
System.out.println(ex.getMessage());
}
#ExceptionHandler(CustomTesException.class)
public final void handleAllExceptio(CustomTesException ex) {
System.out.println("it is in the exception handler");
System.out.println(ex.getMessage());
}
}

How to receive and reply on Spring

I'm trying to deploy a RPC (request/reply pattern) and I'm using RabbitMQ and Spring in the server side because I need dynamic consumers. I can configurate dynamic consumers with SimpleMessageListenerContainer but i don't know how to reply my message.
Here is my class configuration:
#Configuration
public class dynamicConsumerConfig {
private static Properties prop = new Properties();
public static void setPropValues() throws IOException {
File configFile = new File("src/main/resources/config.properties");
InputStream inStream = new FileInputStream(configFile.getAbsolutePath());
prop.load(inStream);
}
#Bean
public Queue slowQueue() {
return new Queue("slowQueue");
}
#Bean
public Queue fastQueue() {
return new Queue("fastQueue");
}
#Bean
public DirectExchange exchange1() {
return new DirectExchange("pdfqueues");
}
#Bean
public Binding slowBind(DirectExchange exchange, Queue slowQueue) {
return BindingBuilder.bind(slowQueue)
.to(exchange)
.with("slow");
}
#Bean
public Binding fastBind(DirectExchange exchange, Queue fastQueue) {
return BindingBuilder.bind(fastQueue)
.to(exchange)
.with("fast");
}
#Bean
public ConnectionFactory connect() throws IOException {
setPropValues();
CachingConnectionFactory connection = new CachingConnectionFactory();
connection.setHost(prop.getProperty("HOST"));
connection.setUsername(prop.getProperty("USER"));
connection.setPassword(prop.getProperty("PASS"));
connection.setPort(Integer.parseInt(prop.getProperty("PORT")));
return connection;
}
#Bean
public SimpleMessageListenerContainer container1(ConnectionFactory connection) throws IOException {
SimpleMessageListenerContainer container = new SimpleMessageListenerContainer();
setPropValues();
container.setConnectionFactory(connection);
container.setQueueNames("slowQueue");
container.setMessageListener(firstListener());
container.setMaxConcurrentConsumers(8);
container.setConcurrentConsumers(1);
container.setConsecutiveActiveTrigger(1);
container.setConsecutiveIdleTrigger(1);
container.setTxSize(1);
container.setPrefetchCount(1);
return container;
}
#Bean
public MessageListener firstListener()
{
return new MessageListener() {
#Override
public void onMessage(Message message) {
PdfBoxService pdfboxservice = new PdfBoxService(prop.getProperty("tmpPath"),prop.getProperty("imagicPath"),prop.getProperty("resources"),
prop.getProperty("tessdata"),prop.getProperty("languages"));
String picture = new String(message.getBody(), StandardCharsets.UTF_8);
List<ImagePair> lip = null;
try {
lip = new ArrayList<ImagePair>();
lip.add(new ImagePair("JPG", picture));
} catch (FileNotFoundException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
ByteArrayOutputStream output= pdfboxservice.ImgToPdf(lip, false, false, false, 1, 1);
} catch (IOException | InterruptedException | TransformerException | BadFieldValueException
| TesseractException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
};
}
In the fuction firstListener() i get the message. In this case is a picture. The picture is converted from JPG to PDF. The PDF is stored in outputvariable.
I need to reply this output in other queue but i don't have tools for do it.
I think that my code is a bad pattern but I don't know how to do a RPC pattern with dynamic consumers using SimpleMessageListenerContainer.
Use a MessageListenerAdapter with a POJO method that returns a result instead of implementing MessageListener yourself.
Starting with version 2.0, a convenient FunctionalInterface has been provided:
#FunctionalInterface
public interface ReplyingMessageListener<T, R> {
R handleMessage(T t);
}
This facilitates convenient configuration of the adapter using Java 8 lamdas:
new MessageListenerAdapter((ReplyingMessageListener<String, String>) data -> {
...
return result;
}));

Integrate my app with Activiti

I have one issue. I integrate my app with Activiti (in the same DB). When I insert, update or delete my entities (not entities's Activiti) by Dao class have use #Transactional but nothing about is being saved to database with no exception.
Here is my config to integrating:
#Configuration
public class ActivitiEngineConfiguration {
private final Logger log = LoggerFactory.getLogger(ActivitiEngineConfiguration.class);
#Autowired
protected Environment environment;
#Bean
public DataSource dataSource() {
SimpleDriverDataSource ds = new SimpleDriverDataSource();
try {
#SuppressWarnings("unchecked")
Class<? extends Driver> driverClass = (Class<? extends Driver>) Class.forName(environment.getProperty("jdbc.driver", "org.postgresql.Driver"));
ds.setDriverClass(driverClass);
} catch (Exception e) {
log.error("Error loading driver class", e);
}
ds.setUrl(environment.getProperty("spring.datasource.url"));
ds.setUsername(environment.getProperty("spring.datasource.username"));
ds.setPassword(environment.getProperty("spring.datasource.password"));
return ds;
}
#Bean(name = "transactionManager")
public PlatformTransactionManager annotationDrivenTransactionManager() {
DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
transactionManager.setDataSource(dataSource());
System.out.println("transactionManager: "+transactionManager);
return transactionManager;
}
#Bean(name="processEngineFactoryBean")
public ProcessEngineFactoryBean processEngineFactoryBean() {
ProcessEngineFactoryBean factoryBean = new ProcessEngineFactoryBean();
factoryBean.setProcessEngineConfiguration(processEngineConfiguration());
return factoryBean;
}
#Bean(name="processEngine")
public ProcessEngine processEngine() {
// Safe to call the getObject() on the #Bean annotated processEngineFactoryBean(), will be
// the fully initialized object instanced from the factory and will NOT be created more than once
try {
return processEngineFactoryBean().getObject();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
#Bean(name="processEngineConfiguration")
public ProcessEngineConfigurationImpl processEngineConfiguration() {
SpringProcessEngineConfiguration processEngineConfiguration = new SpringProcessEngineConfiguration();
processEngineConfiguration.setDataSource(dataSource());
processEngineConfiguration.setDatabaseSchemaUpdate(environment.getProperty("engine.schema.update", "true"));
processEngineConfiguration.setTransactionManager(annotationDrivenTransactionManager());
processEngineConfiguration.setJobExecutorActivate(Boolean.valueOf(
environment.getProperty("engine.activate.jobexecutor", "false")));
processEngineConfiguration.setAsyncExecutorEnabled(Boolean.valueOf(
environment.getProperty("engine.asyncexecutor.enabled", "true")));
processEngineConfiguration.setAsyncExecutorActivate(Boolean.valueOf(
environment.getProperty("engine.asyncexecutor.activate", "true")));
processEngineConfiguration.setHistory(environment.getProperty("engine.history.level", "full"));
String mailEnabled = environment.getProperty("engine.email.enabled");
if ("true".equals(mailEnabled)) {
processEngineConfiguration.setMailServerHost(environment.getProperty("engine.email.host"));
int emailPort = 1025;
String emailPortProperty = environment.getProperty("engine.email.port");
if (StringUtils.isNotEmpty(emailPortProperty)) {
emailPort = Integer.valueOf(emailPortProperty);
}
processEngineConfiguration.setMailServerPort(emailPort);
String emailUsernameProperty = environment.getProperty("engine.email.username");
if (StringUtils.isNotEmpty(emailUsernameProperty)) {
processEngineConfiguration.setMailServerUsername(emailUsernameProperty);
}
String emailPasswordProperty = environment.getProperty("engine.email.password");
if (StringUtils.isNotEmpty(emailPasswordProperty)) {
processEngineConfiguration.setMailServerPassword(emailPasswordProperty);
}
}
// List<AbstractFormType> formTypes = new ArrayList<AbstractFormType>();
// formTypes.add(new UserFormType());
// formTypes.add(new ProcessDefinitionFormType());
// formTypes.add(new MonthFormType());
// processEngineConfiguration.setCustomFormTypes(formTypes);
return processEngineConfiguration;
}
#Bean
public RepositoryService repositoryService() {
return processEngine().getRepositoryService();
}
#Bean
public RuntimeService runtimeService() {
return processEngine().getRuntimeService();
}
#Bean
public TaskService taskService() {
return processEngine().getTaskService();
}
#Bean
public HistoryService historyService() {
return processEngine().getHistoryService();
}
#Bean
public FormService formService() {
return processEngine().getFormService();
}
#Bean
public IdentityService identityService() {
return processEngine().getIdentityService();
}
#Bean
public ManagementService managementService() {
return processEngine().getManagementService();
}
}
DAO Layer:
#Autowired
private SessionFactory sessionFactory;
#Override
#Transactional
public void save(MyEntity obj) {
sessionFactory.getCurrentSession().saveOrUpdate(loaiDanhMuc);
}
Thank all!
I guess #Transactional is not working in this case
Please check following things below:
Check if <tx:annotation-driven /> is defined in your spring xml file.

Transactions with Guice and JDBC - Solution discussion

In my application, I need to use pure JDBC together with Guice. However, Guice doesn't provide any built-in support to manage transactions. guice-persist only provides support based on JPA, which I cannot use.
so I tried to implement a simple solution to manage transactions with Guice and JDBC. here is the first version:
use TransactionHolder to store the transaction per thread.
public class JdbcTransactionHolder {
private static ThreadLocal<JdbcTransaction> currentTransaction = new ThreadLocal<JdbcTransaction>();
public static void setCurrentTransaction(JdbcTransaction transaction) {
currentTransaction.set(transaction);
}
public static JdbcTransaction getCurrentTransaction() {
return currentTransaction.get();
}
public static void removeCurrentTransaction() {
currentTransaction.remove();
}
}
implements a transaction manager for JDBC, for now only begin(), getTransaction(), commit() and rollback() method:
public class JdbcTransactionManager implements TransactionManager {
#Inject
private DataSource dataSource;
#Override
public void begin() throws NotSupportedException, SystemException {
logger.debug("Start the transaction");
try {
JdbcTransaction tran = JdbcTransactionHolder.getCurrentTransaction();
Connection conn = null;
if(tran == null) {
conn = dataSource.getConnection();
}
else {
conn = tran.getConnection();
}
// We have to put the connection in the holder so that we can get later
// from the holder and use it in the same thread
logger.debug("Save the transaction for thread: {}.", Thread.currentThread());
JdbcTransactionHolder.setCurrentTransaction(new JdbcTransaction(conn));
} catch (Exception e) {
throw new RuntimeException(e);
}
}
#Override
public void commit() throws RollbackException, HeuristicMixedException,
HeuristicRollbackException, SecurityException,
IllegalStateException, SystemException {
logger.debug("Commit the transaction");
try {
logger.debug("Get the connection for thread: {}.", Thread.currentThread());
Transaction transaction = JdbcTransactionHolder.getCurrentTransaction();
transaction.commit();
}
catch(Exception e) {
throw new RuntimeException(e);
}
finally {
JdbcTransactionHolder.removeCurrentTransaction();
}
}
#Override
public Transaction getTransaction() throws SystemException {
logger.debug("Get transaction.");
final JdbcTransaction tran = JdbcTransactionHolder.getCurrentTransaction();
if(tran == null) {
throw new DBException("No transaction is availble. TransactionManager.begin() is probably not yet called.");
}
return tran;
}
#Override
public void rollback() throws IllegalStateException, SecurityException,
SystemException {
logger.debug("Rollback the transaction");
try {
logger.debug("Get the transaction for thread: {}.", Thread.currentThread());
Transaction conn = JdbcTransactionHolder.getCurrentTransaction();
conn.commit();
}
catch(Exception e) {
throw new RuntimeException(e);
}
finally {
JdbcTransactionHolder.removeCurrentTransaction();
}
}
}
implement a wrapper for DataSource which can get the current connection from the transaction holder if a transaction has been started:
public class JdbcDataSource implements DataSource {
private final static org.slf4j.Logger logger = LoggerFactory.getLogger(JdbcDataSource.class);
private DataSource dataSource;
public JdbcDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}
#Override
public PrintWriter getLogWriter() throws SQLException {
return dataSource.getLogWriter();
}
#Override
public int getLoginTimeout() throws SQLException {
return dataSource.getLoginTimeout();
}
#Override
public Logger getParentLogger() throws SQLFeatureNotSupportedException {
return dataSource.getParentLogger();
}
#Override
public void setLogWriter(PrintWriter out) throws SQLException {
this.dataSource.setLogWriter(out);
}
#Override
public void setLoginTimeout(int seconds) throws SQLException {
this.dataSource.setLoginTimeout(seconds);
}
#Override
public boolean isWrapperFor(Class<?> arg0) throws SQLException {
return this.isWrapperFor(arg0);
}
#Override
public <T> T unwrap(Class<T> iface) throws SQLException {
return this.unwrap(iface);
}
#Override
public Connection getConnection() throws SQLException {
JdbcTransaction transaction = JdbcTransactionHolder.getCurrentTransaction();
if(transaction != null) {
// we get the connection from the transaction
logger.debug("Transaction exists for the thread: {}.", Thread.currentThread());
return transaction.getConnection();
}
Connection conn = this.dataSource.getConnection();
conn.setAutoCommit(false);
return conn;
}
#Override
public Connection getConnection(String username, String password)
throws SQLException {
JdbcTransaction transaction = JdbcTransactionHolder.getCurrentTransaction();
if(transaction != null) {
// we get the connection from the transaction
logger.debug("Transaction exists for the thread: {}.", Thread.currentThread());
return transaction.getConnection();
}
return this.dataSource.getConnection(username, password);
}
}
then create a DataSourceProvider so that we can inject DataSource to any POJO using guice:
public class DataSourceProvider implements Provider {
private static final Logger logger = LoggerFactory.getLogger(DataSourceProvider.class);
private DataSource dataSource;
public DataSourceProvider() {
JdbcConfig config = getConfig();
ComboPooledDataSource pooledDataSource = new ComboPooledDataSource();
try {
pooledDataSource.setDriverClass(config.getDriver());
} catch (Exception e) {
throw new RuntimeException(e);
}
pooledDataSource.setJdbcUrl(config.getUrl());
pooledDataSource.setUser(config.getUsername());
pooledDataSource.setPassword(config.getPassword() );
pooledDataSource.setMinPoolSize(config.getMinPoolSize());
pooledDataSource.setAcquireIncrement(5);
pooledDataSource.setMaxPoolSize(config.getMaxPoolSize());
pooledDataSource.setMaxStatements(config.getMaxStatementSize());
pooledDataSource.setAutoCommitOnClose(false);
this.dataSource = new JdbcDataSource(pooledDataSource);
}
private JdbcConfig getConfig() {
JdbcConfig config = new JdbcConfig();
Properties prop = new Properties();
try {
//load a properties file from class path, inside static method
prop.load(JdbcConfig.class.getResourceAsStream("/database.properties"));
//get the property value and print it out
config.setDriver(prop.getProperty("driver"));
config.setUrl(prop.getProperty("url"));
config.setUsername(prop.getProperty("username"));
config.setPassword(prop.getProperty("password"));
String maxPoolSize = prop.getProperty("maxPoolSize");
if(maxPoolSize != null) {
config.setMaxPoolSize(Integer.parseInt(maxPoolSize));
}
String maxStatementSize = prop.getProperty("maxStatementSize");
if(maxStatementSize != null) {
config.setMaxStatementSize(Integer.parseInt(maxStatementSize));
}
String minPoolSize = prop.getProperty("minPoolSize");
if(minPoolSize != null) {
config.setMinPoolSize(Integer.parseInt(minPoolSize));
}
}
catch (Exception ex) {
logger.error("Failed to load the config file!", ex);
throw new DBException("Cannot read the config file: database.properties. Please make sure the file is present in classpath.", ex);
}
return config;
}
#Override
public DataSource get() {
return dataSource;
}
and then implement TransactionalMethodInterceptor to manage the transaction for the method with Transactional annotation:
public class TransactionalMethodInterceptor implements MethodInterceptor {
private final static Logger logger = LoggerFactory.getLogger(TransactionalMethodInterceptor.class);
#Inject
private JdbcTransactionManager transactionManager;
#Override
public Object invoke(MethodInvocation method) throws Throwable {
try {
// Start the transaction
transactionManager.begin();
logger.debug("Start to invoke the method: " + method);
Object result = method.proceed();
logger.debug("Finish invoking the method: " + method);
transactionManager.commit();
return result;
} catch (Exception e) {
logger.error("Failed to commit transaction!", e);
try {
transactionManager.rollback();
}
catch(Exception ex) {
logger.warn("Cannot roll back transaction!", ex);
}
throw e;
}
}
}
Finally, the code to put all together so that Guice can inject the instances:
bind(DataSource.class).toProvider(DataSourceProvider.class).in(Scopes.SINGLETON);
bind(TransactionManager.class).to(JdbcTransactionManager.class);
TransactionalMethodInterceptor transactionalMethodInterceptor = new TransactionalMethodInterceptor();
requestInjection(transactionalMethodInterceptor);
bindInterceptor(Matchers.any(), Matchers.annotatedWith(Transactional.class), transactionalMethodInterceptor);
bind(TestDao.class).to(JdbcTestDao.class);
bind(TestService.class).to(TestServiceImpl.class);
I use c3p0 for the datasource pool. so, it works just fine in my test.
I find another related question: Guice, JDBC and managing database connections
but so far I haven't find any similar approach, except something in SpringFramework. but even the implementation in Spring seems quite complex.
I would like to ask if anyone has any suggestion for this solution.
thanks.

Resources