How to use Derby Client in Felix? - java

I want to run Derby Client from within an OSGi bundle. The bundle gets built by Maven so I added a dependency to org.apache.derby:derbyclient. At runtime I get the following exception: java.sql.SQLException: No suitable driver found for jdbc:derby://localhost:1527/testdb.
Interestingly the whole thing works when I use the embedded driver and a dependency to org.apache.derby.derby. I just don't see the difference between those two.
What am I doing wrong and how can I fix it?
Some tidbits:
After some advice I found on the Internet I set the following OSGi header: DynamicImport-Package: *. This fixed problems with the embedded driver but the client still fails.
The version of Derby I use is 10.7.1.1 which should be OSGi enabled (at least it has OSGi headers).

In OSGi it is recommended to not use the DrivverManager to get a connection. The better way is to use a DataSource.
So for derby client you could use this:
ClientDataSource ds = new ClientDataSource();
... // set properties here
Connection connection = dataSource.getConnection();
As the DataSource approach does not fiddle with the classloader it is much more reliable in OSGi.
Additionally it is a good practice to separate the DataSource from your client code and bind it as an OSGi service. This allows to keep the dependency to the database impl out of your code.
The easiest approach is to use pax-jdbc-config and let it create the DataSource for you from a configuration. In your own code you then just bind the DataSource as a service and are fine.
The current release version of pax-jdbc does not yet support the derbyclient but I just added this to the master. So the next release should contain it.

Okay, although not even half an hour passed since I asked the question I found a solution. I don't know how clean it is but it seems to get the job done:
ClassLoader ctxtCl = Thread.currentThread().getContextClassLoader();
try {
Thread.currentThread().setContextClassLoader(getClass().getClassLoader());
try {
Class.forName("org.apache.derby.jdbc.ClientDriver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
dbConnection = DriverManager.getConnection("jdbc:derby://localhost:1527/testdb");
} catch (SQLException e) {
/* log, etc. */
} finally {
Thread.currentThread().setContextClassLoader(ctxtCl);
}

Related

Postgresql JDBC connection error on Android

I am unable to connect a PostgreSQL db on Android. Using JDBC is for development purpose only and will change to proper web service.
I have implemented the PostgreSQL driver in build.gradle as "implementation 'org.postgresql:postgresql:42.2.18.jre7"
My PostgreSQL database server is listening to port: 5433
My computer IP in my network is 192.168.1.103
And the user name and password is set correct
The connection:
Connection con = null;
try
{
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
/* Register jdbc driver class. */
Class.forName("org.postgresql.Driver");
/* Create connection url. */
String postgresConnUrl = "jdbc:postgresql://192.168.1.103:5433/lmsdb";
Properties props = new Properties();
props.setProperty("user","postgres");
props.setProperty("password","xxxxxxx");
props.setProperty("ssl","false");
/* Get the Connection object. */
con = DriverManager.getConnection(postgresConnUrl, props);
}catch(Exception ex)
{
ex.printStackTrace();
}finally
{
return con ;
}
When I change the IP in "postgresConnUrl" to 127.0.0.1 which is set in pg_hba, I get the error
org.postgresql.util.PSQLException: Connection refused. Check that the
hostname and port are correct and that the postmaster is accepting
TCP/IP connections
And when I use my computer's IP address as shown in the connection code above, the connection con = DriverManager.getConnection(postgresConnUrl, props); is returning null. The log shows no exception or errors, but the con is null and I am unable to trace the problem. Any directions to the problem would be helpful.
DriverManager.getConnection(...) cannot return null. Unless there is a severe bug in the implementation, it always returns a non-null connection or throws a SQLException (or RuntimeException or Error as thrown by drivers).
The PostgreSQL driver is likely causing an Error to be thrown (e.g. a NoClassDefFoundError, because the PostgreSQL JDBC driver uses Java features or classes not present on Android). This is hidden by the fact that your finally block will unconditionally return con, and you only catch and log instances of Exception, but not Error. See also Adding return in finally hides the exception
Remove your catch and finally block and let any exception or other Throwable bubble up to the caller, instead of replacing an explicit exception or error with a hidden error (returning null), alternatively have the catch block wrap the exception in a custom exception and throw that custom exception.
I recommend you don't use JDBC on Android. Most recent JDBC drivers are using Java features or classes not present on Android, which can cause all kinds of issues. You mention you're doing this for development purposes, but I would suggest that creating or mocking your REST API and using that from the start will save you a lot of headaches and unnecessary development work.
I tried using older version of JDBC and I was able to connect. The newer version of JDBC does not seem to be compatible with Android and result in error as you posted. But, still I can see many people are using JDBC as it is easy although Rest API is better option but requires additional skills.

Use of Java Smack 4.3.4 in a JUnit Testcase in Maven

I am working on a Java library with some services based on xmpp. For XMPP communication, I use Smack version 4.3.4. The development has so far been without problems and I have also created some test routines that can all be run without errors. After I migrated to a Maven project to generate a FatJar, I wanted to convert the executable test cases into JUnit tests. Unexpectedly, an error occurs, the reason of which I cannot explain. As I said, the code can be run outside of JUnit without any problems.
Below is the simplified test code (establishing a connection to the xmpp server):
#Test
public void connect()
{
Builder builder = XMPPTCPConnectionConfiguration.builder();
builder.setSecurityMode(SecurityMode.disabled);
builder.setUsernameAndPassword("iec61850client", "iec61850client");
builder.setPort(5222);
builder.setSendPresence(true);
try
{
builder.setXmppDomain("127.0.0.1");
builder.setHostAddress(InetAddress.getByName("127.0.0.1"));
}
catch (Exception e)
{
e.printStackTrace();
}
XMPPTCPConnectionConfiguration config = builder.build();
XMPPTCPConnection c = new XMPPTCPConnection(config);
c.setReplyTimeout(5000);
try
{
c.connect().login();
}
catch (Exception e)
{
e.printStackTrace();
}
}
And here is the error message I get:
Exception in thread "Smack Reader (0)" java.lang.AssertionError
at org.jivesoftware.smack.tcp.XMPPTCPConnection$PacketReader.parsePackets(XMPPTCPConnection.java:1154)
at org.jivesoftware.smack.tcp.XMPPTCPConnection$PacketReader.access$1000(XMPPTCPConnection.java:1092)
at org.jivesoftware.smack.tcp.XMPPTCPConnection$PacketReader$1.run(XMPPTCPConnection.java:1112)
In Smack it boils down to this 'assert' instruction:
assert (config.getXMPPServiceDomain().equals(reportedServerDomain));
Any idea what the problem might be or similar problems? I'm grateful for any help!
Thanks a lot,
Markus
If you look at the source code you will find that reportedServerDomain is extracted from the server's stream open tag. In this case the xmpp domain reported by the server does not match the one that is configured. This should usually not happen, but I assume it is related to the way you run the unit tests. Or more precisely, related to the remote server or mocked server that is used in the tests. If you enable smack's debug output, you will see the stream open tag and the 'from' attribute and its value. Compare this with the configured XMPP service domain in the ConnectionConfiguration.

Hive JDBC connection problems

I am trying to connect to Hive2 server via JDBC with kerberos authentication. After numerous attempts to make it work, I can't get it to work with the Cloudera driver.
If someone can help me to solve the problem, I can greatly appreciate it.
I have this method:
private Connection establishConnection() {
final String driverPropertyClassName = "driver";
final String urlProperty = "url";
Properties hiveProperties = config.getMatchingProperties("hive.jdbc");
String driverClassName = (String) hiveProperties.remove(driverPropertyClassName);
String url = (String) hiveProperties.remove(urlProperty);
Configuration hadoopConfig = new Configuration();
hadoopConfig.set("hadoop.security.authentication", "Kerberos");
String p = config.getProperty("hadoop.core.site.path");
Path path = new Path(p);
hadoopConfig.addResource(path);
UserGroupInformation.setConfiguration(hadoopConfig);
Connection conn = null;
if (driverClassName != null) {
try {
UserGroupInformation.loginUserFromKeytab(config.getProperty("login.user"), config.getProperty("keytab.file"));
Driver driver = (Driver) Class.forName(driverClassName).newInstance();
DriverManager.registerDriver(driver);
conn = DriverManager.getConnection(url, hiveProperties);
} catch (Throwable e) {
LOG.error("Failed to establish Hive connection", e);
}
}
return conn;
}
URL for the server, that I am getting from the properties in the format described in Cloudera documentation
I am getting an exception:
2018-05-05 18:26:49 ERROR HiveReader:147 - Failed to establish Hive connection
java.sql.SQLException: [Cloudera][HiveJDBCDriver](500164) Error initialized or created transport for authentication: Peer indicated failure: Unsupported mechanism type PLAIN.
at com.cloudera.hiveserver2.hivecommon.api.HiveServer2ClientFactory.createTransport(Unknown Source)
at com.cloudera.hiveserver2.hivecommon.api.ZooKeeperEnabledExtendedHS2Factory.createClient(Unknown Source)
...
I thought, that it is missing AuthMech attribute and added AuthMech=1 to the URL. Now I am getting:
java.sql.SQLNonTransientConnectionException: [Cloudera][JDBC](10100) Connection Refused: [Cloudera][JDBC](11640) Required Connection Key(s): KrbHostFQDN, KrbServiceName; [Cloudera][JDBC](11480) Optional Connection Key(s): AsyncExecPollInterval, AutomaticColumnRename, CatalogSchemaSwitch, DecimalColumnScale, DefaultStringColumnLength, DelegationToken, DelegationUID, krbAuthType, KrbRealm, PreparedMetaLimitZero, RowsFetchedPerBlock, SocketTimeOut, ssl, StripCatalogName, transportMode, UseCustomTypeCoercionMap, UseNativeQuery, zk
at com.cloudera.hiveserver2.exceptions.ExceptionConverter.toSQLException(Unknown Source)
at com.cloudera.hiveserver2.jdbc.common.BaseConnectionFactory.checkResponseMap(Unknown Source)
...
But KrbHostFQDN is already specified in the principal property as required in the documentation.
Am I missing something or is this documentation wrong?
Below is the one of the similar kind of problem statement in Impala (just JDBC engine changes others are same) that is resolved by setting "KrbHostFQDN" related properties in JDBC connection string itself.
Try to use the URL below. Hopefully works for u.
String jdbcConnStr = "jdbc:impala://myserver.mycompany.corp:21050/default;SSL=1;AuthMech=1;KrbHostFQDN=myserver.mycompany.corp;KrbRealm=MYCOMPANY.CORP;KrbServiceName=impala"
I suppose that if you are not using SSL=1 but only Kerberos, you just drop that part from the connection string and don't worry about setting up SSL certificates in the java key store, which is yet another hassle.
However in order to get Kerberos to work properly we did the following:
Install MIT Kerberos 4.0.1, which is a kerberos ticket manager. (This is for Windows)
This ticket manager asks you for authentication every time you initiate a connection, creates a ticket and stores it in a kerberos_ticket.dat binary file, whose location can be configured somehow but I do not recall exactly how.
Finally, before launching your JAVA app you have to set an environment variable KRB5CCNAME=C:/path/to/kerberos_ticket.dat. In your java app, you can check that the variable was correctly set by doing System.out.println( "KRB5CCNAME = " + System.getenv( "KRB5CCNAME" ) ). If you are working with eclipse or other IDE you might even have to close the IDE,set up the environment variable and start the IDE again.
NOTE: this last bit is very important, I have observed that if this variable is not properly set up, the connection wont be established...
In Linux, instead MIT Kerberos 4.0.1, there is a program called kinit which does the same thing, although without a graphical interface, which is even more convenient for automation.
I wanted to put it in the comment but it was too long for the comment, therefore I am placing it here:
I tried your suggestion and got another exception:
java.sql.SQLException: [Cloudera]HiveJDBCDriver Error
creating login context using ticket cache: Unable to obtain Principal
Name for authentication .
May be my problem is, that I do not have environment variable KRB5CCNAME set.
I, honestly, never heard about it before.
What is supposed to be in that ticket file.
I do have, however, following line in my main method:
System.setProperty("java.security.krb5.conf", "path/to/krb5.conf");
Which is supposed to be used by
UserGroupInformation.loginUserFromKeytab(config.getProperty("login.user"), config.getProperty("keytab.file"));
to obtain the kerberos ticket.
To solve this issue update Java Cryptography Extension for the Java version that you use in your system.
Here's the link when you can download JCE for Java 1.7
Uncompress and overwrite those files in $JDK_HOME/jre/lib/security
Restart your computer.

Connecting MATLAB and MySQL with the JDBC Driver

I bought the book Undocumented MATLAB by Yair Altmam; in chapter 2.2 of the book he discusses database connectivity and using the JDBC to connect to databases. I followed the steps and text of the book. I downloaded the mysql-connector-java-5.1.30-bin.jar(from http://dev.mysql.com/downloads/connector/j/) and typed up the following code as detailed in the book:
clear all
%%Initializing JDBC driver
try
import java.sql.DriverManager;
javaclasspath('mysql-connector-java-5.1.30-bin.jar')
driverClassName = 'com.mysql.jdbc.Driver';
try
%This works when the class/JAR is on the static Java classpath
%Note: driver automatically registers with DriverManager
java.lang.Class.forName(driverClassName);
catch
try
%Try loading from the dynamic Java path
classLoader = com.mathworks.jmi.ClassLoaderManager.getClassLoaderManager;
driverClass = classLoader.loadClass(driverClassName);
catch %#ok<*CTCH>
try
%One more attempt, using the system class-loader
classLoader = java.lang.ClassLoader.getSystemClassLoader;
%An alternative, using the MATLAB Main Thread's context
%classLoader =
%java.lang.Thread.currentThread.getContextClassLoader;
driverClass = classLoader.loadClass(driverClassName);
catch
%One final attempt-load directly, like this:
driverClass = eval(driverClassName); %#ok<*NASGU>
%Or like this (if the driver name is known in advance):
driverClass = com.mysql.jdbc.Driver;
end
end
%Now manually register the driver with the DriverManager
%Note: silently fails if driver is not in the static classpath
DriverManager.registerDriver(driverClass.newInstance);
end
%continue with database processing
catch
error(['JDBC driver ' driverClassName ' not found!']);
%do some failover activity
end
%% Connecting to a database
import java.sql.*;
connStr = 'jdbc:mysql://localhost:3306/test';
con = DriverManager.getConnection(connStr,'root','1234');
Every attempt to run the code I get the following error message:
??? Java exception occurred:
java.sql.SQLException: No suitable driver found for
jdbc:mysql://localhost:3306/test
at java.sql.DriverManager.getConnection(Unknown Source)
at java.sql.DriverManager.getConnection(Unknown Source)
Error in ==> undocumentedMATLAB at 45
con = DriverManager.getConnection(connStr,'root','1234');
Has anyone experienced this problem or have any suggestion that could help me resolve it.
Thanks in advance.
My first suspicion is your java class path. Instead of:
javaclasspath('mysql-connector-java-5.1.30-bin.jar')
Use
javaaddpath('C:\full\path\to\mysql-connector-java-5.1.30-bin.jar')
If that is not the problem, lets skip the DriverManager (doesn't really help much) and see if the code below works, (or where it fails).
d = com.mysql.jdbc.Driver;
urlValid = d.acceptsURL('jdbc:mysql://localhost:3306/test'); %Should return true
props = java.util.Properties;
props.put('user','root'); props.put('password','1234');
con = d.connect('jdbc:mysql://localhost:3306/test',props)
The DriverManager construct doesn't really help much. It seems to be designed to allow a developer to load up a bunch of drivers, and then connect to any supported database without knowing or caring what the DB implementation was (e.g. Mysql, Postgresql, Oracle etc.) I have never seen this as a useful feature. I think (hope?) that this is being used less in favor of a DataSource construct.
Regardless, if this is your first time connecting Mysql to Matlab, you probably are best just directing using the provided Driver class.

Documentum DFS: Timeout for service calls

I'm working with the DFS Java API and was wondering whether anyone knows a simple way to configure a client-side timeout for service-calls that can be configured on the service context, for example?
I have experienced some rare occasions where a Documentum repository was not responding, that's why I am considering a general timeout for all DFS calls.
For testing a hanging service call, I created a dummy TBO implementation that simply blocks the thread for 10 minutes when updating the document:
#Override
public void saveEx(boolean keepLock, String versionLabels) throws DfException {
if (isNew() == false) {
try {
Thread.sleep(1000*60*10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
super.saveEx(keepLock, versionLabels);
}
I'm not sure if this behaves exactly like a hanging service call, but at least in my tests it worked as expected - my invocations of the update method of the Object Service took about 10minutes.
Is there any configuration I have not yet found, or maybe a runtime-property to pass to the service context to configure the timeout?
I would prefer using existing features of DFS for this instead of implementing my own mechanism.
Have you tried editing the value in dfs-runtime.properties? I don't think the timeout can be context-specific, but you should be able to change it for the client as a whole.
Reposted from https://community.emc.com/message/3249#3249
"Please see the Server runtime startup settings section of the Deployment guide.
The following list describes the precedence that dfs-runtime.properties files take depending on their location:
local-dfs‑runtime.properties file in the local classpath
runtime properties file specified with ‑Ddfs.runtime.properties.file
dfs‑runtime.properties packaged with emc‑dfs‑rt.jar
For example, settings in the local-dfs‑runtime.properties file on the local classpath will take precedence of identical settings in the dfs‑runtime.properties file that is located in emc‑dfs‑rt.jar or the one specified with the ‑D parameter. The DFS application must be restarted after any changes to the configuration. As a best practice, use the provided configuration file that is deployed in the emc‑dfs‑rt.jar file for your base settings and use an external file to override settings that you specifically wish to change."

Categories

Resources