How to manually specify db connection for Quartz JobStoreTX - quartz-scheduler

I'm trying to configure Quartz in clustered mode in a Ktor application.
I want to avoid property file so I'm doing the scheduler initialization programmatically.
This is what I achieved so far:
val jobStore = JobStoreTX()
jobStore.setIsClustered(true)
jobStore.dataSource = "datasourceName" //Here is the issue - I want to inject datasource object, not the name
DirectSchedulerFactory.getInstance().createScheduler(
"DS-SCHEDULER",
"AUTO",
SimpleThreadPool(),
jobStore)
val scheduler = DirectSchedulerFactory.getInstance().getScheduler("DS-SCHEDULER")
scheduler.start()
I see that JobStoreTX class only allows to inject datasource name but I would like to provide a DataSource object because Ktor application does not have a naming service.
Is there any alternative way to achieve this?

Figured out how to solve.
So, given a datasource name "myDs", Quartz JobStoreSupport class will lookup for the datasource by name like this:
DBConnectionManager.getInstance().getConnection(getDataSource())
where getDatasource() is an internal method that returns the datasource name string ("myDs").
So what I had to do was to manually add the connection provider to the DBConnectionManager before initializing the scheduler like this:
DBConnectionManager.getInstance().addConnectionProvider(
"myDs",
HikariCpPoolingConnectionProvider(
"dbDriver",
"dbUrl",
"username",
"password",
10,
"validation Query"
)
)
and then I can initalize the scheduler:
val jobStore = JobStoreTX()
jobStore.setIsClustered(true)
jobStore.dataSource = "myDs
val simpleThreadPool = SimpleThreadPool()
simpleThreadPool.threadCount = 5
DirectSchedulerFactory.getInstance().createScheduler(
"Scheduler Name,
"AUTO",
simpleThreadPool,
jobStore
)
Scheduler Factory is then able to lookup the datasource and getting DB connections.

Related

Create message liseners dynamically for the topics

I was analysing a problem on creating a generic consumer library which can be deployed in multiple microservices ( all of them are spring based) . The requirement is to have around 15-20 topics to listen .If we use annotation based kafka listener ,we need to add more code for each microservice . Is there any way where we can create the consumers dynamically based on some xml file where each consumer can have these data injected
topic
groupid
partition
filter (if any)
With annotations ,the design is very rigid .The only way I can think of is ,we can create messagelisteners after parsing xml config and each topic will have its own concurrentmessagelistenercontainer .
Is there any alternative better approach available using spring ?
P.S: I am little new to spring & kafka . Please let me know if there is confusion in explaning the requirements
Thanks,
Rajasekhar
Maybe you can use topic patterns. Take a look at consumer properties. E.g. the listener
#KafkaListener(topicPattern = "topic1|topic2")
will listen to topic1 and topic2.
If you need to create a listener dynamically extra care must be taken, because you must shutdown it.
I would use a similar approach as spring's KafkaListenerAnnotationBeanPostProcessor. This post processor is responsible for processing #KafkaListeners.
Here is a proposal of how it could work:
public class DynamicEndpointRegistrar {
private BeanFactory beanFactory;
private KafkaListenerContainerFactory<?> containerFactory;
private KafkaListenerEndpointRegistry endpointRegistry;
private MessageHandlerMethodFactory messageHandlerMethodFactory;
public DynamicEndpointRegistrar(BeanFactory beanFactory,
KafkaListenerContainerFactory<?> containerFactory,
KafkaListenerEndpointRegistry endpointRegistry, MessageHandlerMethodFactory messageHandlerMethodFactory) {
this.beanFactory = beanFactory;
this.containerFactory = containerFactory;
this.endpointRegistry = endpointRegistry;
this.messageHandlerMethodFactory = messageHandlerMethodFactory;
}
public void registerMethodEndpoint(String endpointId, Object bean, Method method, Properties consumerProperties,
String... topics) throws Exception {
KafkaListenerEndpointRegistrar registrar = new KafkaListenerEndpointRegistrar();
registrar.setBeanFactory(beanFactory);
registrar.setContainerFactory(containerFactory);
registrar.setEndpointRegistry(endpointRegistry);
registrar.setMessageHandlerMethodFactory(messageHandlerMethodFactory);
MethodKafkaListenerEndpoint<Integer, String> endpoint = new MethodKafkaListenerEndpoint<>();
endpoint.setBeanFactory(beanFactory);
endpoint.setMessageHandlerMethodFactory(messageHandlerMethodFactory);
endpoint.setId(endpointId);
endpoint.setGroupId(consumerProperties.getProperty(ConsumerConfig.GROUP_ID_CONFIG));
endpoint.setBean(bean);
endpoint.setMethod(method);
endpoint.setConsumerProperties(consumerProperties);
endpoint.setTopics(topics);
registrar.registerEndpoint(endpoint);
registrar.afterPropertiesSet();
}
}
You should then be able to register a listener dynamically. E.g.
DynamicEndpointRegistrar dynamicEndpointRegistrar = ...;
MyConsumer myConsumer = ...; // create an instance of your consumer
Properties properties = ...; // consumer properties
// the method that should be invoked
// (the method that's normally annotated with KafkaListener)
Method method = MyConsumer.class.getDeclaredMethod("consume", String.class);
dynamicEndpointRegistrar.registerMethodEndpoint("endpointId", myConsumer, method, properties, "topic");

How to create custom schema with Corda Vault Extension

From Corda documents, it says we can have custom schema in Vault Extension.
However there is not much clarity for Vault Extension which should have ability to create/manage custom database schema pertaining to node vault database.
Are we going to publish API in feature release of Corda
Inside flows, the node exposes a JDBC connection that allows you to write native custom SQL queries (as a vault extension). You can access this JDBC connection using serviceHub.jdbcSession().
If your question is about how to write a custom schema then please see the existing Corda Persistence API docs.
You can then query that custom schema using the new Vault Query API - please see the existing [Corda Vault Query API][3] docs.
Just to add an example to the above, here's a custom schema for the Yo! CorDapp. See YoSchemaV1 below:
// State.
data class State(val origin: Party,
val target: Party,
val yo: String = "Yo!") : ContractState, QueryableState {
override val participants get() = listOf(target)
override val contract get() = Yo()
override fun toString() = "${origin.name}: $yo"
override fun supportedSchemas() = listOf(YoSchemaV1)
override fun generateMappedObject(schema: MappedSchema) = YoSchemaV1.YoEntity(this)
object YoSchemaV1 : MappedSchema(Yo.State::class.java, 1, listOf(YoEntity::class.java)) {
#Entity #Table(name = "yos")
class YoEntity(yo: State) : PersistentState() {
#Column var origin: String = yo.origin.name.toString()
#Column var target: String = yo.target.name.toString()
#Column var yo: String = yo.yo
}
}
}
In short, your state object needs to implement QueryableState, as above.
The full CorDapp is available here: https://github.com/roger3cev/yo-cordapp
Cheers

Context lookup for EJB client returns $Proxy119 object instead of actual class object

I am simply invoking a EJB 3.0 like this in JBoss:
MyEJB myEJB = (MyEJB) initialContext.lookup("");
Now the lookup works fine. The object returned has the viewType,moduleName, beanName as expected. But it throws this exception:
2015-04-10 18:49:08,266 ERROR [org.teiid.CONNECTOR] (Worker0_QueryProcessorQueue1128) Connector worker process failed for atomic-request=GfxN/Obks1QK.1.1.0: java.lang.ClassCastException: com.sun.proxy.$Proxy119 cannot be cast to com.MyEJB
How do I cast it to the object that I intend to use?
here's a sample example of code :
HelloLocalHome helloHome;
HelloLocal hello;
//In your main or init method,
// 1. Retreive the Home Interface using a JNDI Lookup
// Retrieve the initial context for JNDI.
// No properties needed when local
Context context = new InitialContext();
// Retrieve the home interface using a JNDI lookup using
// the java:comp/env bean environment variable
// specified in web.xml
helloHome = (HelloLocalHome) context.lookup("java:comp/env/ejb/HelloBean");
//2. Narrow the returned object to be an HelloHome object.
// Since the client is local, cast it to the correct object type.
//3. Create the local Hello bean instance, return the reference
hello = (HelloLocal)helloHome.create();
//And the call will be as follows :
hello.sayHello("James Earl")
It turns out the correct way to do that is this:
StatelessEJBLocator<MyEjb> locator = new StatelessEJBLocator(
MyEjb.class, APP_NAME, MODULE_NAME,
MyEjbRemote.class.getSimpleName(), DISTINCT_NAME);
MyEjb myEjb = org.jboss.ejb.client.EJBClient.createProxy(locator);

How to set UserID and Password in EnterpriseLibrary 6.0

I have coded like the below:
#Code
DatabaseProviderFactory factory = new DatabaseProviderFactory();
database = factory.Create("DBinstanceName");
ConfigFile Entries
<oracleConnectionSettings>
<add name="CNQ" />
</oracleConnectionSettings>
<connectionStrings>
<add name="CNQ" connectionString=" Min Pool Size=0;Connection Lifetime=120;Max Pool Size=50; Data Source=(DESCRIPTION = (ADDRESS_LIST = (ADDRESS = (PROTOCOL = TCP)(HOST= XXXX.com)(PORT=1521))) (CONNECT_DATA = (SID = cnq) (SERVER = DEDICATED) ) );"
providerName="Oracle.DataAccess.Client" />
</connectionStrings>
With the above code and config settings, the DatabaseObject is created perfectly. When I verify the connectionstring it has the values what I had mentioned in the connnection string. So far good.
Now, I have to add the UserId & Password to the connection string at the runtime. There is no methods I could find to add the user credentials to the existing connection string. Becuase, in the Database object the connection string is READ ONLY.
The only way I find is to set in the configuration file[App.config], which is not the way we want, because for every user, we have a separate userid and password in the Oracle database.
In fact, I had tried by settings the connections at the command object, and passed the command object to the execute reader, even then also the enterprise library 6.0, not taking the connection we set in the command object.
Please help us how to set the userid and password in the runtime.
Thanks in advance
In order to set connection string values at runtime you will have to programmatically create your database objects. For example:
Database database = new GenericDatabase(GetConnectionString(),
DbProviderFactories.GetFactory("Oracle.DataAccess.Client"));
Or if you are using OracleDatabase something like:
OracleDatabase database = new OracleDatabase(GetConnectionString());
You could use extension methods to hide a bit of the ugliness:
DatabaseProviderFactory factory = new DatabaseProviderFactory();
Database db = factory.CreateWithConnectionString(GetConnectionString(),
DbProviderFactories.GetFactory("Oracle.DataAccess.Client"));
db = factory.CreateOracleDatabase(GetConnectionString());
public static class DatabaseProviderFactoryExtensions
{
public static Database CreateWithConnectionString(this DatabaseProviderFactory factory,
string connectionString,
DbProviderFactory dbProviderFactory)
{
return new GenericDatabase(connectionString, dbProviderFactory);
}
public static Database CreateOracleDatabase(this DatabaseProviderFactory factory,
string connectionString)
{
return new OracleDatabase(connectionString);
}
}
Another way to approach the issue if you know what connections you will have in advance (still at runtime but perhaps at application startup) is to use the DatabaseFactory.SetDatabases method to return the correct database based on a key. Unfortunately, the method only takes a single string so you can't specify nicely the username and password but you might be able to do something like this:
DatabaseFactory.SetDatabases(() => GetDatabase("Default"),
(dbName) => GetDatabase(dbName));
Database db = DatabaseFactory.CreateDatabase();
public Database GetDatabase(string dbName)
{
string connectionString = GetConnectionString(dbName);
return new OracleDatabase(connectionString);
}
Where the GetConnectionString method can create the proper connection string based on a name. However, I'm guessing this last way might not be the best given your description.
Thanks for your response.
Because I am using the Enterprise Library 6.0, only the First answer only works.
Database database = new GenericDatabase(GetConnectionString(),
DbProviderFactories.GetFactory("Oracle.DataAccess.Client"));
[or]
Oralce.DataAccess.Client.OralceClientFactory ocf = new Oracle.DataAccess.Client.OracleClientFactory();
Database database = new GenericDatabase(GetConnectionString(), ocf);
Thanks

Entity Framework - Database First without config

I'm developing a class library that deals with an exiting db using EF. I want to avoid the consumer of the class library (and .exe or a web site) to have in the *.config file the Entity connection string. I want the connection string set a run-time.
How do I set the connection string with Database First approach? There is no constructor overload that takes a connection string and when I created one (in a separate partial class) I got an "UnintentionalCodeFirstException".
I have reviewed already the following links:
Is there a way to change connection string in database first?. Its about modifying the connection string in the config file, which I want to avoid, also because it would recycle the process (in the case of a web app)
How can l use Entity Framework without App.config. Not good because it uses ObjectContext and I need the context generated when I imported the database.
There is a constructor on DbContext that takes a DbConnection, and you need to use an EntityConnection object for it:
SqlConnectionStringBuilder sqlBuilder = new SqlConnectionStringBuilder();
// Set the properties for the data source.
sqlBuilder.DataSource = "server name";
sqlBuilder.InitialCatalog = "database name";
sqlBuilder.IntegratedSecurity = true;
// Build the SqlConnection connection string.
string providerString = sqlBuilder.ToString();
var entityBuilder = new EntityConnectionStringBuilder();
// Initialize the EntityConnectionStringBuilder.
//Set the provider name.
entityBuilder.Provider = "System.Data.SqlClient";
// Set the provider-specific connection string.
entityBuilder.ProviderConnectionString = providerString;
// Set the Metadata location.
entityBuilder.Metadata = #"res://*/Model1.csdl|res://*/Model1.ssdl|res://*/Model1.msl";
using(var context = new YourDbContext(entityBuilder.ToString())){
//do stuff here
}
The important thing to note is the metadata part - "Model1" obviously needs to be replaced for your model name.
Ref: http://msdn.microsoft.com/en-us/library/bb738533.aspx
EDIT 20/02/2013 22:25
So as an addition you'll need to extend the created DbContext class with a partial class that adds a constructor to support the above code, like this:
public partial class YourDbContext
{
public YourDbContext(string connection) : base(connection) {}
}
This class needs to be in the same namespace as the DbContext that is generated by the entity framework wizard.