Ektorp CouchDB test connection - java

I'm working on a Java application which uses the Ektorp Framework to communicate with a CouchDB. I use the following code to create a new CouchDbInstance:
HttpClient httpClient = new StdHttpClient.Builder()
.host("localhost")
.port("5984")
.username("")
.password("");
/* no user name and password required because, its admin party */
CouchDbInstance couchDbInstance = new StdCouchDbInstance(httpClient);
Now I want to test the connection to the CouchDB before I create/modify etc. documents. There is no method for testing the connection. Do you have a tip for me?

I'm using Ektorp in my current project and we're testing this with couchDbConnector.getAllDatabases(), catching DbAccessExceptions.
This has the slight advantage over checkIfDbExists() of being totally agnostic of the actual databases configured on the CouchDB server, and not referencing any application-specific configuration for connection checking just feels a little cleaner.

You can use CouchDbConnector#getDbInfo()

I'm currently working on a project using ektorp and I am testing my database connection like this.
Step 1 -- Connect to the HttpClient as you have done
HttpClient httpClient = new StdHttpClient.Builder()
.host("localhost")
.port("5984")
.username("")
.password("");
/* no user name and password required because, its admin party */
CouchDbInstance couchDbInstance = new StdCouchDbInstance(httpClient);
Step 2 -- Create a CouchDbInstance
CouchDbInstance dbInstance = new StdCouchDbInstance(httpClient);
Step 3 -- Use CouchDbConnector to connect to a specific database in your localhost CouchDB (in this example my database is called albums but you just put in the name for whatever database you are connecting to in place of albums from where you are coding)
CouchDbConnector albums = dbInstance.createConnector("albums", true);
Step 4 -- You can print off the name of the database you are connected to like this.
System.out.println(albums.getDatabaseName());
You could also create an endpoint that would print the name of the database you are connected to in the browser by creating a method of type string with
return albums.getDatabaseName();
I hope this is helpful. I used ektorp's reference documentation to learn this. It took me a while to figure out how to use ektorp like this and I am still learning!

Related

Java async driver for MongoDB doesn't work on replica set when "primary" is changed

I have some troubles with the usage of java async driver (3.8.1).
I'll describe my environment:
I have a replica set (rs0) with 3 istances: let me call them A,B,C.
In my application I use Mongo and two different java driver, sync and async.
At the beginning I reached no problems but when the primary went down (and come up after some minutes changing its behavior as secondary) the part of code when I use async driver was not able to use transactions and session.
The error is the following:
com.mongodb.MongoClientException: Sessions are not supported by the MongoDB cluster to which this client is connected
at com.mongodb.async.client.MongoClientImpl$1.onResult(MongoClientImpl.java:90)
at com.mongodb.async.client.MongoClientImpl$1.onResult(MongoClientImpl.java:83)
at com.mongodb.async.client.ClientSessionHelper$2.onResult(ClientSessionHelper.java:77)
at com.mongodb.async.client.ClientSessionHelper$2.onResult(ClientSessionHelper.java:73)
at com.mongodb.internal.connection.BaseCluster$ServerSelectionRequest.onResult(BaseCluster.java:433)
at com.mongodb.internal.connection.BaseCluster.handleServerSelectionRequest(BaseCluster.java:309)
at com.mongodb.internal.connection.BaseCluster.access$800(BaseCluster.java:65)
at com.mongodb.internal.connection.BaseCluster$WaitQueueHandler.run(BaseCluster.java:482)
at java.lang.Thread.run(Unknown Source)
2019-01-21 17:02:01.906 ERROR 17560 --- [271de4498944329] org.mongodb.driver.client : Callback onResult call produced an error
java.lang.NullPointerException: null
at it.mypackage.mongo.service.ProcessoDocumentService$1.onResult(ProcessoDocumentService.java:124)
at it.mypackage.mongo.service.ProcessoDocumentService$1.onResult(ProcessoDocumentService.java:1)
at com.mongodb.internal.async.ErrorHandlingResultCallback.onResult(ErrorHandlingResultCallback.java:49)
at com.mongodb.async.client.MongoClientImpl$1.onResult(MongoClientImpl.java:90)
at com.mongodb.async.client.MongoClientImpl$1.onResult(MongoClientImpl.java:83)
at com.mongodb.async.client.ClientSessionHelper$2.onResult(ClientSessionHelper.java:77)
at com.mongodb.async.client.ClientSessionHelper$2.onResult(ClientSessionHelper.java:73)
at com.mongodb.internal.connection.BaseCluster$ServerSelectionRequest.onResult(BaseCluster.java:433)
at com.mongodb.internal.connection.BaseCluster.handleServerSelectionRequest(BaseCluster.java:309)
at com.mongodb.internal.connection.BaseCluster.access$800(BaseCluster.java:65)
at com.mongodb.internal.connection.BaseCluster$WaitQueueHandler.run(BaseCluster.java:482)
at java.lang.Thread.run(Unknown Source)
Just FYI, if I comment the part of code when I use session and transactions, the error is a classic timeout, as the driver was not longer able to find replica set anymore.
Someone could help me? What I'm missing?
This is how I create my MongoClient:
connectionString = new ConnectionString("mongodb://address1:27017,address2:27018,address3:27019/?replicaSet=rs0");
MongoClientSettings settings = MongoClientSettings.builder().applyConnectionString(connectionString)
.build();
settings = settings.builder().credential(credential).build();
asyncMongoClientInstance = MongoClients.create(settings);
I found the solution by myself, as the wise man once said: "If you want an help, find it at the end of your arm".
Let's us focus on this part of code:
connectionString = new connectionString("mongodb://address1:27017,address2:27018,address3:27019/?replicaSet=rs0");
MongoClientSettings settings = MongoClientSettings.builder().applyConnectionString(connectionString)
.build();
settings = settings.builder().credential(credential).build();
asyncMongoClientInstance = MongoClients.create(settings);
I'm reallocating the settings object to another object without the connection string.
So, async library doesn't know anymore where to address the connection.
Why I did that? I wanted to dinamically add credentials to the settings. But is not possible in this way. So I created two different settings object, one with credentials and one without.
MongoClientSettings settings = MongoClientSettings.builder().applyConnectionString(connectionString).credential(credential).build();
It definitely works with this object now.

MongoDB: how to create an authenticated db via java driver

I'm trying to create an authenticate database in MongoDB 2.6 using java driver v 2.12.
In particular I need to create a user accessing to admin collection.
Any suggestion?
Thanks.
Here my solution:
MongoClient mcAdmin = new MongoClient(
configuration.getServerAddresses(),
Arrays.asList(MongoCredential.createMongoCRCredential(
MONGODB_ADMIN_USERNAME, "admin",
MONGODB_ADMIN_PASSWORD.toCharArray())));
try {
mcAdmin.setWriteConcern(WriteConcern.JOURNALED);
DB db = mcAdmin.getDB(userDbName);
BasicDBObject commandArguments = new BasicDBObject();
commandArguments.put("user", userUsername);
commandArguments.put("pwd", userPassword);
String[] roles = { "readWrite" };
commandArguments.put("roles", roles);
BasicDBObject command = new BasicDBObject("createUser",
commandArguments);
db.command(command);
} finally {
mcAdmin.close();
}
Doing this in Java code is not the best way to do it, and except for very rare use cases (writing an admin application for MongoDB) even one I would strongly advice against.
Security risk
First of all, your application would need extremely high privileges, namely userAdminAnyDatabase or userAdmin on the admin database, which more or less grants the same rights: creating a superuser at will. To put it in other words: this code would be a high security risk.
Granting roles and rights on a database is an administrative task and for good reasons should be decoupled from an application accessible by arbitrary users.
Technical problems
Activating authentication from a client simply is impossible. The mongod instance in question has to be started with authentication enabled. Furthermore, you would have to save to create a user with the mentioned roles before you could have your app administer users. The problem: you would have to store the password for that user somewhere. Unless you encrypt it, you basically store the most powerful password for your MongoDB databases and cluster in cleartext. And if you encrypt it, you have to pass the key for decryption to your application at some point in a secure manner. And all this to break best practices ("Separation of concerns")?

XStorable storeToURL and WebDav

I have seen multiple threads regarding the use of XStorable.storeToURL and vnd.sun.star.webdav://domain:8080//path/to/document_library to save OO documents to a webdav library folder. However, I have not seen a posting where someone has successfully used this in Java. While the use of the UCB vnd.sun.star.webdav://domain:8080//path/to/document_library/doc.odt works when using the File, Save menu options within OO Writer, I am prompted for a username and password. Supplying user and password via vnd.sun.star.webdav://user:password#domain:8080/ has not worked for me. I need to use this method from within a Java class to save a OO document. Has anyone had success using the following or something similar?
xStorable.storeToURL("vnd.sun.star.webdav://domain:8080/path/to/document_library/doc.odt", storeProps)
In the OO Developer's Guide, there is a paragraph regarding WebDav authentication:
DAV resources that require authentication are accessed using the interaction handler mechanism of the UCB. The DAV content calls an interaction handler supplied by the client to let it handle an authentication request. The implementation of the interaction handler collects the user name or password from a location, for example, a login dialog, and supplies this data as an interaction response.
Maybe this is related to the issue? If so, how to use an interaction handler for the authentication when trying to storeToURL via webdav?
Adding InteractionHandler was the issue. With this added, documents can be saved via storeToURL and passing the handler in as an argument:
String oooExeFolder = "C:/OpenOffice/program";
XComponentContext xLocalContext = BootstrapSocketConnector.bootstrap(oooExeFolder);
Object serviceManager = xLocalServiceManager.createInstanceWithContext("com.sun.star.task.InteractionHandler", xLocalContext);
XInteractionHandler xHandler = (XInteractionHandler)UnoRuntime.queryInterface( XInteractionHandler.class, serviceManager);
PropertyValue[] storeProps = new PropertyValue[1];
storeProps[0] = new PropertyValue();
storeProps[0].Name = "InteractionHandler";
storeProps[0].Value = xHandler;
xStorable.storeToURL("vnd.sun.star.webdav://domain:8080/path/to/document_library/doc.odt", storeProps);

Can I globally set the timeout of HTTP connections?

I have a program that uses javax.xml.ws.Service to call a remote service defined by a WSDL. This program runs on the Google App Engine which, by default, sets the HTTP connection timeout to 5 seconds{1}. I need to increase this timeout value since this service often takes a long time to respond, but since this request is not being made with URLConnection, I cannot figure out how to call URLConnection.setReadTimeout(int){2}, or otherwise change the timeout.
Is there any way to globally set the HTTP connection timeout on the App Engine? And, for purposes of sharing knowledge, how would one go about solving this sort of problem generally?
{1}: https://developers.google.com/appengine/docs/java/urlfetch/overview#Requests
{2}: http://docs.oracle.com/javase/1.5.0/docs/api/java/net/URLConnection.html#setReadTimeout(int)
You could try setting the sun.net.client.defaultConnectTimeout and sun.net.client.defaultReadTimeout system properties documented here, e.g.
System.setProperty("sun.net.client.defaultReadTimeout", "30000");
System.setProperty("sun.net.client.defaultConnectTimeout", "30000");
EDIT
Sorry, just re-read and noticed this is on Google App Engine. I don't know for sure, but given the litigious relationship Google and Oracle have lately, I'm guessing GAE doesn't run the Oracle JVM. I'll leave this here in case someone else runs into a similar problem.
Try this:
Port port = service.getPort(endPointInterface); //or another "getPort(...)"
((BindingProvider) port).getRequestContext()
.put(BindingProviderProperties.REQUEST_TIMEOUT, 30);
See https://developers.google.com/appengine/docs/java/urlfetch/usingjavanet
You can do something like this to get a URLConnection:
URL url = new URL("http://www.example.com/atom.xml");
URLConnection tempConnection = url.openConnection();
tempConnection.setReadTimeout(10);
For App Engine with JAX-WS you have to set the request context (tested today with SDK 1.9.15). For normal machines you cannot go higher than 60s and would have to switch to the bigger machines (Bx) for better use a task queue.
For local testing you would normally use BindingProviderProperties.CONNECT_TIMEOUT and BindingProviderProperties.REQUEST_TIMEOUT, but they are not on the App Engine JRE White List and your code inspection might constantly warn you about that.
The equivalent strings can be used though:
com.sun.xml.internal.ws.connect.timeout
com.sun.xml.internal.ws.connect.timeout
For deployment to App Engine:
com.sun.xml.ws.connect.timeout
com.sun.xml.ws.request.timeout
A full example how to apply that to auto-generated code from JAX-WS 2.x, values have to be provided in milliseconds:
#WebEndpoint(name = "Your.RandomServicePort")
public YourServiceInterface getYourRandomServicePort() {
YourRandomServiceInterface port = super.getPort(YOURRANDOMSERVICE_QNAME_PORT, YourRandomServiceInterface.class);
Map<String, Object> requestContext = ((BindingProvider)port).getRequestContext();
requestContext.put("com.sun.xml.ws.connect.timeout", 10000);
requestContext.put("com.sun.xml.ws.request.timeout", 10000);
return port;
}

Call to DataSource.getConnection not returning the expected connection

I have the following code:
Hashtable env1 = new Hashtable();
env1.put(javax.naming.Context.INITIAL_CONTEXT_FACTORY,"com.ibm.websphere.naming.WsnInitialContextFactory");
log.info("Executed step 1");
env1.put(javax.naming.Context.PROVIDER_URL, "iiop://myhost.com:9301");
log.info("Executed step 2");
Context ctx = new InitialContext(env1);
DataSource ds = (DataSource)ctx.lookup("jdbc/mydatasource");
log.info("Excecuted lookup ="+ds);
conn = ds.getConnection();
I have the previous code in an standalone application that is connecting to WAS 6.1.0.3 in order to retrieve a connection from the datasource. The code is very straighforward, and I have seen the same code working in a different environment, but in this case when I call getConnection I get an exception. The datasource is WAS has the proper authentication alias set and when the connection is tested it works OK from the WAS side, but the previous code won't work.
If I change this line: conn = ds.getConnection();
to this: conn = ds.getConnection("username","password");
Then the code will work! But that's not what I want since the connections in the datasource should already have the credentials set. I was initially thinking this was a Sybase problem, but it's also happening with Oracle, so would rather say I have a problem with WAS.
If you are curious about the exceptions, for Sybase I get:
java.sql.SQLException: JZ004: User name property missing in DriverManager.getConnection(..., Properties).DSRA0010E: SQL State = JZ004, Error Code = 0
at com.sybase.jdbc2.jdbc.ErrorMessage.raiseError(ErrorMessage.java:569)
at com.sybase.jdbc2.tds.LoginToken.<init>(LoginToken.java:128)
at com.sybase.jdbc2.tds.Tds.doLogin(Tds.java:506)
at com.sybase.jdbc2.tds.Tds.login(Tds.java:449)
at com.sybase.jdbc2.jdbc.SybConnection.tryLogin(SybConnection.java:254)
at com.sybase.jdbc2.jdbc.SybConnection.regularConnect(SybConnection.java:230)
at com.sybase.jdbc2.jdbc.SybConnection.<init>(SybConnection.java:200)
at com.sybase.jdbc2.jdbc.SybPooledConnection.<init>(SybPooledConnection.java:72)
at com.sybase.jdbc2.jdbc.SybConnectionPoolDataSource.createConnection(SybConnectionPoolDataSource.java:138)
at com.sybase.jdbc2.jdbc.SybDriver.connect(SybDriver.java:485)
at com.sybase.jdbc2.jdbc.SybDriver.connect(SybDriver.java:517)
at com.sybase.jdbc2.jdbc.SybDataSource.getConnection(SybDataSource.java:227)
at com.sybase.jdbc2.jdbc.SybConnectionPoolDataSource.getPooledConnection(SybConnectionPoolDataSource.java:74)
at com.ibm.ws.rsadapter.spi.InternalGenericDataStoreHelper$1.run(InternalGenericDataStoreHelper.java:897)
at com.ibm.ws.security.util.AccessController.doPrivileged(AccessController.java:118)
at com.ibm.ws.rsadapter.spi.InternalGenericDataStoreHelper.getPooledConnection(InternalGenericDataStoreHelper.java:892)
at com.ibm.ws.rsadapter.spi.WSRdbDataSource.getPooledConnection(WSRdbDataSource.java:1181)
at com.ibm.ws.rsadapter.spi.WSManagedConnectionFactoryImpl.createManagedConnection(WSManagedConnectionFactoryImpl.java:1047)
at com.ibm.ws.rsadapter.spi.WSDefaultConnectionManagerImpl.allocateConnection(WSDefaultConnectionManagerImpl.java:81)
at com.ibm.ws.rsadapter.jdbc.WSJdbcDataSource.getConnection(WSJdbcDataSource.java:431)
at com.ibm.ws.rsadapter.jdbc.WSJdbcDataSource.getConnection(WSJdbcDataSource.java:400)
And for Oracle I get this one:
java.sql.SQLException: invalid arguments in callDSRA0010E: SQL State = null, Error Code = 17,433
at oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:112)
at oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:146)
at oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:208)
at oracle.jdbc.driver.T4CConnection.logon(T4CConnection.java:236)
at oracle.jdbc.driver.PhysicalConnection.<init>(PhysicalConnection.java:420)
at oracle.jdbc.driver.T4CConnection.<init>(T4CConnection.java:165)
at oracle.jdbc.driver.T4CDriverExtension.getConnection(T4CDriverExtension.java:35)
at oracle.jdbc.driver.OracleDriver.connect(OracleDriver.java:801)
at oracle.jdbc.pool.OracleDataSource.getPhysicalConnection(OracleDataSource.java:297)
at oracle.jdbc.pool.OracleDataSource.getConnection(OracleDataSource.java:221)
at oracle.jdbc.pool.OracleConnectionPoolDataSource.getPhysicalConnection(OracleConnectionPoolDataSource.java:157)
at oracle.jdbc.pool.OracleConnectionPoolDataSource.getPooledConnection(OracleConnectionPoolDataSource.java:94)
at oracle.jdbc.pool.OracleConnectionPoolDataSource.getPooledConnection(OracleConnectionPoolDataSource.java:75)
at com.ibm.ws.rsadapter.spi.InternalGenericDataStoreHelper$1.run(InternalGenericDataStoreHelper.java:897)
at com.ibm.ws.security.util.AccessController.doPrivileged(AccessController.java:118)
at com.ibm.ws.rsadapter.spi.InternalGenericDataStoreHelper.getPooledConnection(InternalGenericDataStoreHelper.java:892)
at com.ibm.ws.rsadapter.spi.WSRdbDataSource.getPooledConnection(WSRdbDataSource.java:1181)
at com.ibm.ws.rsadapter.spi.WSManagedConnectionFactoryImpl.createManagedConnection(WSManagedConnectionFactoryImpl.java:1047)
at com.ibm.ws.rsadapter.spi.WSDefaultConnectionManagerImpl.allocateConnection(WSDefaultConnectionManagerImpl.java:81)
at com.ibm.ws.rsadapter.jdbc.WSJdbcDataSource.getConnection(WSJdbcDataSource.java:431)
at com.ibm.ws.rsadapter.jdbc.WSJdbcDataSource.getConnection(WSJdbcDataSource.java:400)
In both cases I won't the exception if I pass the credentials to the getConnection method
Thanks for your advice.
Short answer: external clients don't get to use the authentication alias data
Longer Answer:
From the WAS J2C connection factory documentation:
The alias that you configure for component-managed authentication does not apply to all clients that must access the secured resource. External Java clients with Java Naming and Directory Interface (JNDI) access can look up a Java 2 Connector (J2C) resource such as a data source or Java Message Service (JMS) queue. However, they are not permitted to take advantage of the component-managed authentication alias defined on the resource. This alias is the default value that is used when the getConnection() method does not specify any authentication data, like user and password, or a value for ConnectionSpec. If an external client needs to get a connection, it must assume responsibility for the authentication by passing it through arguments on the getConnection() call.
It's been a long time since I've done anything with WebSFEAR^H^H^H^Hphere, but it looks to me that you have a configuration problem. There was a special screen where you'd create credentials (user/pass) and later you'd apply those credentials to the created data source. It looks like that your configured data source hasn't got credentials applied.
Even after defining the user/password values as custom properties I found that the connections for Oracle weren't working. After many days, I just found that the development server is running an old WAS 6.1 version, the problem I'm having was fixed in WAS 6.1.0.5: PK32838: J2CA0046E WHEN USING USING CUSTOM PROP PASSWORD ON DATASOURECE
I tried my code in a different WAS server with an updated WAS fix pack level and... it worked without introducing a single change in the code or in the configuration. So the solution is to upgrade the WAS server.
Thanks.

Categories

Resources