How to use a JNDI Resource in a JAX-RS (Jersey) Application? - mysql

I'm trying to set up a connection to my database through a Tomcat JNDI resource. I've been looking at many articles today and I can't seem to find an answer.
In my server.xml I have:
<GlobalNamingResources>
<Resource name="jdbc/MyDB" auth="Container" type="javax.sql.DataSource"
maxActive="100" maxIdle="30" maxWait="10000"
username="tomcat" password="...."
driverClassName="com.mysql.jdbc.Driver"
url="jdbc:mysql://localhost:3333/tomcat?autoReconnect=true"/>
.....
</GlobalNamingResources>
In my web service, I attempt to access the resource with:
InitialContext ctx = new InitialContext();
DataSource data = (DataSource)ctx.lookup("java:comp/env/jdbc/MyDB");
Connection conn = data.getConnection();
When I run the code, I get this exception:
Nov 2, 2011 1:06:20 PM com.sun.jersey.spi.container.ContainerResponse mapMappableContainerException
SEVERE: The exception contained within MappableContainerException could not be mapped to a response, re-throwing to the HTTP container
javax.naming.NameNotFoundException: Name jdbc is not bound in this Context
...
I have the newest mysql-connector-java-5.1.18-bin.jar in both my web-app's lib and my tomcat lib.
Can you please help me get this working?

I use this code, with only the name of the resource, and it works:
private Connection getConnection(){
final Context ctx = new InitialContext();
final DataSource ds = (DataSource) ctx.lookup("jdbc/MyDB");
if (ds != null)
{
return ds.getConnection();
}
else
{
}
}

We just need to mention the jndi name after java:
In your case:
InitialContext ctx = new InitialContext();
DataSource data = (DataSource)ctx.lookup("java:/jdbc/MyDB");
Connection conn = data.getConnection();
Because you configured in your server.xml as below:
<GlobalNamingResources>
<Resource name="jdbc/MyDB" auth="Container" type="javax.sql.DataSource"
maxActive="100" maxIdle="30" maxWait="10000"
username="tomcat" password="...."
driverClassName="com.mysql.jdbc.Driver"
url="jdbc:mysql://localhost:3333/tomcat?autoReconnect=true"/>
.....
</GlobalNamingResources>

My solution was to switch to a properties file for the database information and then utilize it with entity manager.
import java.io.FileReader;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.servlet.ServletException;
import org.eclipse.persistence.config.EntityManagerProperties;
import org.eclipse.persistence.config.PersistenceUnitProperties;
...
Properties properties = new Properties();
FileReader fr = new FileReader(Constants.Config.getPropertiesFile());
properties.load(fr);
// connect to the database
Map<String,String> emMap = new HashMap<String,String>();
emMap.put(PersistenceUnitProperties.APP_LOCATION, Constants.Config.getAppDir());
emMap.put(EntityManagerProperties.JDBC_USER, properties.getProperty("db.username"));
emMap.put(EntityManagerProperties.JDBC_PASSWORD, properties.getProperty("db.password"));
// iterate over these properties attempting to read them in and connect to the url
List<?> dbProps = Collections.list(properties.keys());
Collections.sort(dbProps, new Comparator<Object>() {
#Override
public int compare(Object o1, Object o2) {
return o1.toString().compareTo(((String)o2));
}
});
for(Object propKey : dbProps){
// support multiple database key/values in the eform db.url, db.url1, ... db.urlN
if(!propKey.toString().matches("db.url\\d*")){
continue;
}
String dbLocation = properties.getProperty(propKey.toString());
try {
if(dbLocation == null) continue;
emMap.put(EntityManagerProperties.JDBC_URL, dbLocation);
EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("db", emMap);
em = entityManagerFactory.createEntityManager();
// ensure we're connected by executing a no-op query
em.createNativeQuery("select current_database()").getSingleResult(); // will only work for postgresql
properties.put("db.connected", dbLocation);
break;
}
catch (javax.persistence.PersistenceException e) {
Utility.logger(DataHolder.class).error("Couldn't connect to " + dbLocation);
}
}

Related

Mulesoft - Load a JSON or XML properties file into a global variable

I am trying to load a relatively simple configuration file into a variable that I can access globally within via MEL. I don't want to use a typical properties field because my structure is not flat.
I was able to get somewhat close by loading the file as a bean as follows, but this left me with a giant string, rather than a hashmap (I can see why, I just didn't know how to fix it):
<spring:bean id="ClientConfiguration" name="ClientConfiguration" class="java.lang.String" scope="singleton">
<spring:constructor-arg>
<spring:bean id="Test" name="org.springframework.util.FileCopyUtils" class="org.springframework.util.FileCopyUtils" factory-method="copyToByteArray">
<spring:constructor-arg type="java.io.InputStream" value="classpath:client-configuration.json"/>
</spring:bean>
</spring:constructor-arg>
</spring:bean>
Thoughts on appropriate or better ways to do this?
Here is the solution.
Class file:
package com.example;
import java.io.File;
import java.util.HashMap;
import java.util.Map;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.type.TypeReference;
public class JSONUtil {
File in;
public File getIn() {
return in;
}
public void setIn(File in) {
this.in = in;
}
public Map<String, Object> getConfigAsMap(){
try{
ObjectMapper mapper = new ObjectMapper();
TypeReference<HashMap<String,Object>> typeRef = new TypeReference<HashMap<String,Object>>() {};
Map<String, Object> map = mapper.readValue( in, typeRef);
System.out.println(map);
return map;
} catch(Exception exception){
exception.printStackTrace();
return null;
}
}
}
Config:
<spring:bean id="JSONUtil" class="com.example.JSONUtil" >
<spring:property name="in" value="classpath:client-configuration.json"/>
</spring:bean>
<spring:bean name="ClientConfiguration" factory-bean="JSONUtil" factory-method="getConfigAsMap" />
This is working and JSON Config is loaded as a Map.

JDBI json response o MySql database

i´m trying to use a endpoint to question mysql database in eclipse using tomcat 7 as server but it´s always giving me this error, does someone solved this problem with jdbi
type Exception report
message java.sql.SQLException: No suitable driver found for
jdbc:mysql://127.0.0.1/demo
The code:
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Response;
import org.json.JSONException;
import org.json.JSONObject;
import org.skife.jdbi.v2.DBI;
import org.skife.jdbi.v2.Handle;
#Path("/jdbiservice")
public class JdbiService {
#Path("{f}")
#GET
#Produces("application/json")
public Response convertFtoCfromInput(#PathParam("f") int f) throws JSONException {
DBI dbi = new DBI("jdbc:mysql://127.0.0.1/demo", "user", "pass");
Handle h = dbi.open();
BatchExample b = h.attach(BatchExample.class);
Something s =b.findById(f);
h.close();
JSONObject jsonObject = new JSONObject(s);
String result = jsonObject.toString();
return Response.status(200).entity(result).build();
}
}
Hi have the jar connector file on the eclipse project path and inside tomcat lib folder.
This worked for me
package com.crunchify.restjersey;
import java.util.List;
import javax.naming.InitialContext;
import javax.sql.DataSource;
import javax.ws.rs.*;
import javax.ws.rs.core.Response;
import org.json.*;
import org.skife.jdbi.v2.*;
#Path("/sensorservice")
public class SensorService {
#Path("{id}")
#DELETE
public Response deleteSensorById(#PathParam("id") int id) {
///...
try {
DBI dbi = new DBI(SensorService.getDataSource());
Handle h = dbi.open();
SensorInterface si = h.attach(SensorInterface.class);
si.deleteById(id);;
h.close();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
String result = "Deleted";
return Response.status(200).entity(result).build();
}
private static DataSource getDataSource (){
DataSource ds = null;
InitialContext contex;
try {
contex = new InitialContext();
ds = ( DataSource) contex.lookup("java:comp/env/jdbc/jndiname");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return ds;
}
}
at webinf/webxml
<resource-ref>
<description>DB Connection</description>
<res-ref-name>jdbc/mysql</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
on tomcat context file
<Resource
name = "jdbc/jndiname"
auth = "Container"
type = "javax.sql.DataSource"
maxActive ="100"
maxIdle = "30"
maxWait = "10000"
driverClassName = "com.mysql.jdbc.Driver"
url = "jdbc:mysql://localhost:3306/schema"
username = "user"
password = "pass"
/>
You should include the mysql driver in your dependencies.
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.34</version>
</dependency>

How to test an EJB service class that invokes a REST call?

I'm aware that some developer say it's not a unit test to invoke a method of an EJB which requests a web resource. However, please do not argue about that in this thread! I think it is worthwhile to do it.
my Test: testng class --> EJB method --> rest resource
Setup:
Wildfly 8.1
TestNG 6.8.8
jboss-jaxrs-api_1.1_spec, 1.0.1.Final
This is my testing class.
import org.testng.Assert;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import com.doe.webapp.model.general.geoinfo.GeoInfo;
public class GeoIPBeanTest {
#DataProvider(name = "ipAdresses")
public static Object[][] primeNumbers() {
return new Object[][] {
{ "127.0.0.1", true }, // localhost
{ "80.218.114.61", true } }; // real IP
}
#Test(dataProvider = "ipAdresses")
public void getGeoInfoByIp(String ipAddress, boolean isExpectedTrue) {
GeoIPBean geoIpBean = new GeoIPBean();
GeoInfo geoInfo = null;
try {
geoInfo = geoIpBean.getGeoInfoByIp(ipAddress);
} catch (Exception ex) {
Assert.fail(ex.getLocalizedMessage());
}
}
}
This is my class under test.
import javax.ejb.Singleton;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Invocation.Builder;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.MediaType;
import com.doe.webapp.model.general.geoinfo.GeoInfo;
#Singleton
public class GeoIPBean {
private static final String IPV4_PATTERN = "^(([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\.){3}([01]?\\d\\d?|2[0-4]\\d|25[0-5])$";
Map<String, GeoInfo> geoInfoCache = new HashMap<String, GeoInfo>();
// Service Description is here http://freegeoip.net/
static final String GEO_SERICE_URL = "http://freegeoip.net/";
static final String FORMAT = "json";
public GeoInfo getGeoInfoByIp(String ipAddress) {
if(!isValidIp(ipAddress)){
//TODO log invalid IP as warning
return null;
}
GeoInfo geoInfo = geoInfoCache.get(ipAddress);
if (geoInfo == null) {
Client client = ClientBuilder.newClient();
// Invoke the service.
WebTarget webTarget = client.target(GEO_SERICE_URL + FORMAT + "/"
+ ipAddress);
//geoInfo
Builder builder = webTarget.request(MediaType.APPLICATION_JSON);
geoInfo = builder.get(GeoInfo.class);
}
return geoInfo;
}
public static boolean isValidIp(String ipAddress) {
if(ipAddress == null)
return false;
Pattern pattern = Pattern.compile(IPV4_PATTERN);
Matcher matcher = pattern.matcher(ipAddress);
return matcher.matches();
}
}
This EJB works when I run it in the container. It does NOT work in a testNG case.
Client client = ClientBuilder.newClient();
This line in the EJB returnS the error.
java.lang.AssertionError: java.lang.ClassNotFoundException: org.glassfish.jersey.client.JerseyClientBuilder
at org.testng.Assert.fail(Assert.java:94)
at com.doe.webapp.service.general.geoinfo.GeoIPBeanTest.getGeoInfoByIp(GeoIPBeanTest.java:25)
I first thought it is because I have annotated the wildfly library with scope provided ...
<!-- JBOSS JAX REST 2.0 FRAMEWORK -->
<dependency>
<groupId>org.jboss.spec.javax.ws.rs</groupId>
<artifactId>jboss-jaxrs-api_1.1_spec</artifactId>
<version>1.0.1.Final</version>
</dependency>
<!-- RS client library -->
<dependency>
<groupId>javax.ws.rs</groupId>
<artifactId>javax.ws.rs-api</artifactId>
<version>2.0.1</version>
</dependency>
... but Wildfly is using RestEasy and not Jersey. Then I added ...
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-server</artifactId>
<version>1.18.1</version>
</dependency>
... but did NOT help neither.
In Wildfly, they have been using RESTEasy as the default rest provider. It states,
RESTEasy is bundled with JBoss/Wildfly and completely integrated as per the requirements of Java EE 6.
Therefore you have to remove RESTEasy dependencies defore you use Jersey with Jboss/Wildfly. Eventhough I haven't done that, there can be many resources which guides to do that. (Check these links.)
Or else, as an alternative, you can use RESTEasy instead of Jersey.

Configure SSL certificates with Hibernate, Spring and JDBC

I'm trying to move from an unencrypted JDBC connection using a username and password to log in to my MySQL database server, to a connection using SSL and certificate-based authentication. I'm using Hibernate with Spring MVC. My WebAppConfig file looks like this:
package com.****.PolicyManager.init;
import java.util.Properties;
import javax.annotation.Resource;
import javax.sql.DataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.orm.hibernate4.HibernateTransactionManager;
import org.springframework.orm.hibernate4.LocalSessionFactoryBean;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.view.JstlView;
import org.springframework.web.servlet.view.UrlBasedViewResolver;
#Configuration
#ComponentScan("com.sprhib")
#EnableWebMvc
#EnableTransactionManagement
#PropertySource("classpath:application.properties")
public class WebAppConfig {
private static final String PROPERTY_NAME_DATABASE_DRIVER = "db.driver";
private static final String PROPERTY_NAME_DATABASE_PASSWORD = "db.password";
private static final String PROPERTY_NAME_DATABASE_URL = "db.urlSSL";
private static final String PROPERTY_NAME_DATABASE_USERNAME = "db.username";
private static final String PROPERTY_NAME_HIBERNATE_DIALECT = "hibernate.dialect";
private static final String PROPERTY_NAME_HIBERNATE_SHOW_SQL = "hibernate.show_sql";
private static final String PROPERTY_NAME_ENTITYMANAGER_PACKAGES_TO_SCAN = "entitymanager.packages.to.scan";
#Resource
private Environment env;
#Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(env.getRequiredProperty(PROPERTY_NAME_DATABASE_DRIVER));
dataSource.setUrl(env.getRequiredProperty(PROPERTY_NAME_DATABASE_URL));
dataSource.setUsername(env.getRequiredProperty(PROPERTY_NAME_DATABASE_USERNAME));
dataSource.setPassword(env.getRequiredProperty(PROPERTY_NAME_DATABASE_PASSWORD));
return dataSource;
}
#Bean
public LocalSessionFactoryBean sessionFactory() {
LocalSessionFactoryBean sessionFactoryBean = new LocalSessionFactoryBean();
sessionFactoryBean.setDataSource(dataSource());
sessionFactoryBean.setPackagesToScan(env.getRequiredProperty(
PROPERTY_NAME_ENTITYMANAGER_PACKAGES_TO_SCAN));
sessionFactoryBean.setHibernateProperties(hibProperties());
return sessionFactoryBean;
}
private Properties hibProperties() {
Properties properties = new Properties();
properties.put(PROPERTY_NAME_HIBERNATE_DIALECT,
env.getRequiredProperty(PROPERTY_NAME_HIBERNATE_DIALECT));
properties.put(PROPERTY_NAME_HIBERNATE_SHOW_SQL,
env.getRequiredProperty(PROPERTY_NAME_HIBERNATE_SHOW_SQL));
return properties;
}
#Bean
public HibernateTransactionManager transactionManager() {
HibernateTransactionManager transactionManager =
new HibernateTransactionManager();
transactionManager.setSessionFactory(sessionFactory().getObject());
return transactionManager;
}
#Bean
public UrlBasedViewResolver setupViewResolver() {
UrlBasedViewResolver resolver = new UrlBasedViewResolver();
resolver.setPrefix("/WEB-INF/pages/");
resolver.setSuffix(".jsp");
resolver.setViewClass(JstlView.class);
return resolver;
}
}
And my properties config file (application.properties) as follows:
#DB properties:
db.driver=com.mysql.jdbc.Driver
db.url=jdbc:mysql://localhost:3306/PolicyManager
db.urlSSL=jdbc:mysql://localhost:3306/PolicyManager?autoReconnect=true&verifyServerCertificate=false&useSSL=true&requireSSL=true
db.username=myuser
db.password=mypass
#Hibernate Configuration:
hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect
hibernate.show_sql=true
entitymanager.packages.to.scan=com.****.PolicyManager.model
I've generated the right certificates inside /etc/mysql/certs and have edited my.cnf to point to then, but can't find any info online about how to configure my specific method of database initialisation to use certificate-based authentication to remove the need to store my database username and password in plain text on the server.
Can anyone suggest a solution or point me to a tutorial that uses this WebAppConfig.java file (hib properties, DriverManagerDataSource and LocalSessionFactoryBean) for it's configuration?
The MySQL guide has information on what to do on the client side, this bug also has some detailed information.
It basically comes done to the following steps
Create a keystore and truststore with your clients certificate
Configure your environment (or a MysqlDataSource) to use these keystore and truststore
Configure the connection URL properly (which is what you apparently already have done).
And that should be it. The key is to have the correct certificates on the client side.
More information:
Secure JDBC connection to MySQL from GlassFish
Secure JDBC connection to MySQL from Java
MySQL SSL Documentation

How to configure tomcat to work with mysql in OpenShift?

I just discovered OpenShift and i love it! And i would like to try it with a tomcat app that communicates with mysql.I was able to install tomcat through this tutorial
and my tomcat server is up and running !I also installed mysql and phpmyadmin,but now i have to deploy my servlet in the tomcat server .My servlet communicates with mysql but i cant find where to insert the variables that Openshift give me !Does anyone have any idea?
Thnx in advandce Andi :)
OPENSHIFT VARIABLES ARE:
Root User :andi
RootPassword: andi
Connection URL: mysql://$OPENSHIFT_MYSQL_DB_HOST:$OPENSHIFT_MYSQL_DB_PORT/
MY SERVLET:
import java.io.IOException;
import java.io.PrintWriter;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.mysql.jdbc.Connection;
import com.mysql.jdbc.PreparedStatement;
#WebServlet("/HelloWorldServlet")
public class HelloWorldServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
public HelloWorldServlet() {
super();
}
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
String titulli = request.getParameter("titulli");
String ingredientet = request.getParameter("ingredientet");
String receta = request.getParameter("receta");
final String url = "jdbc:mysql://localhost/andi";
final String user = "andi";
final String password = "andi";
try {
// jdbc try
Class.forName("com.mysql.jdbc.Driver");
Connection con = (Connection) DriverManager.getConnection(url, user,
password);
// insert values into the first table
PreparedStatement s = (PreparedStatement) con
.prepareStatement("INSERT INTO recetat(titulli,ingredientet,receta) VALUES (?,?,?)");
s.setString(1, titulli);
s.setString(2, ingredientet);
s.setString(3, receta);
s.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
PrintWriter out = response.getWriter();
out.println("Receta u ruajt me sukses ne server !");
System.out.println(titulli+ingredientet+receta);
}
}
like you can see i dont know where to insert the
Connection URL: mysql://$OPENSHIFT_MYSQL_DB_HOST:$OPENSHIFT_MYSQL_DB_PORT/
variable...
OpenShift puts the MySQL host and port as environment variables on exactly that name. In Java terms, they are available by
String host = System.getenv("OPENSHIFT_MYSQL_DB_HOST");
String port = System.getenv("OPENSHIFT_MYSQL_DB_PORT");
Then, compose the JDBC URL as follows
String url = String.format("jdbc:mysql://%s:%s/andi", host, port);
The normal approach, however, is to create a connection pooled datasource in context.xml and obtain that by JNDI instead.
Somewhat related - you can now install tomcat directly (without following the DIY steps) but running
rhc app create <name> jbossews-1.0
JBoss EWS is a maintained and supported version of Tomcat from Red Hat - all the same bits. Also, starting next week the rhc client tools will support
rhc app create <name> tomcat6
To make it even simpler.