H2 db file in custom location - java

I am starting H2 db in embedded mode. By default h2 db file is getting created in users directory. I have requirement of creating in a custom location. The custom location should be read from environment variable ( Example %MY_HOME%= C:\TEST).
The database file should be created in c:\TEST. What changes should I make in web.xml to do the same?
Thanks in advance

You can add you custom location by setting db.url property of H2.
for example :
If your database name is DBNAME then you can set db.url in web.xml with your custom location in following manner :
jdbc:h2:file:C:\\Test\\DBNAME
If you are using Hibernate in your application then you can build session factory for H2 database in following manner :
private static SessionFactory buildSessionFactory()
{
String methodName = "buildSessionFactory -->";
_logger.debug(methodName + Constants.CALLED);
try
{
// Create the SessionFactory from hibernate.cfg.xml
Configuration configuration = new Configuration();
URL resourceURL = HibernateUtil.class.getClassLoader().getResource("hibernate.cfg.xml");
_logger.debug(resourceURL);
configuration = configuration.configure(resourceURL);
//Here you can set your custom url for H2 database.
String url = "jdbc:h2:file:C:\\Test\\DBNAME;MV_STORE=FALSE;MVCC=TRUE;DB_CLOSE_ON_EXIT=TRUE;FILE_LOCK=NO";
_logger.debug("Database URL " + url);
_logger.debug("Build Session Factory URL: " + url);
configuration = configuration.setProperty("hibernate.connection.url", url);
ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder().applySettings(configuration.getProperties()).build();
_logger.debug("Session factory built");
_logger.debug(Constants.END);
return configuration.buildSessionFactory(serviceRegistry);
}
catch (Throwable ex)
{
_logger.debug("Failed to create session factory");
_logger.error("Initial SessionFactory creation failed.", ex);
ex.printStackTrace();
throw new ExceptionInInitializerError(ex);
}
}

I got an answer for my query. We can set init parameters in two ways.
1) web.xml, Generally everyone uses.
2) contextInitialized will be method called as call back method while tomcat is getting started. In that method you can set the init parameters by using instance of servletContext clas.

Related

Attach logged user when printing any error

I have a SpringBoot backend with logback configured. Authentication is achieved using a OncePerRequestFilter and setting the authentication in the SecurityContextHolder context.
My goal is to print the loggedUser username whenever logback prints an error. My attempt was to add a variable (${LOGGED_USER}) to the logback pattern and then set this variable in the OncePerRequestFilter using the code below:
final Context context = (Context) LoggerFactory.getILoggerFactory();
final JoranConfigurator configurator = new JoranConfigurator();
configurator.setContext(context);
context.putProperty("LOGGED_USER", username);
try {
configurator.doConfigure(Objects.requireNonNull(getClass().getResource("/logback.xml")));
} catch (JoranException e) {
logger.error("Error while configuring logger", e);
}
This works fine in localhost environment. When in production, however, when an error is generated the logger outputs several times, showing every logged user name. It seems to me that my code is creating a new logger context for every request and they are all outputting the error at the same time. I am out of ideas and looking for help!
Thanks in advance
Did you try using Mapped Diagnostic Context to store the username. Access it in the pattern as %X{LOGGED_USER}
final Context context = (Context) LoggerFactory.getILoggerFactory();
final JoranConfigurator configurator = new JoranConfigurator();
configurator.setContext(context);
MDC.put("LOGGED_USER", username);
try {
configurator.doConfigure(Objects.requireNonNull(getClass().getResource("/logback.xml")));
} catch (JoranException e) {
logger.error("Error while configuring logger", e);
}
EDIT-
Since you are using OncePerRequestFilter, this answer by another user may help you

How to load driver dynamically for Hibernate?

I am loading drivers dynamically for JDBC. It works fine, however this DriverManager becomes useless when I try to open a hibernate session
org.hibernate.service.classloading.spi.ClassLoadingException: Specified JDBC Driver com.mysql.jdbc.Driver could not be loaded
Here is the code
public class TestHibernateSessionFactory {
public void test() throws MalformedURLException, InstantiationException, IllegalAccessException, ClassNotFoundException, SQLException {
URL u = new URL("jar:file:/C:\\Users\\...\\mysql-connector-java-5.1.40-bin.jar!/");
String classname = "com.mysql.jdbc.Driver";
URLClassLoader ucl = new URLClassLoader(new URL[] { u });
Driver d = (Driver)Class.forName(classname, true, ucl).newInstance();
DriverManager.registerDriver(new DriverLoader(d));
Connection con = DriverManager.getConnection("jdbc:mysql://localhost:3306", "admin", "password");
// this is the proof that DriverManager loaded and works fine
System.out.println("CONNECTION OBJECT WORKS FINE: " + con);
// Now I want to try this same technique with hibernate
Session session = null;
Transaction tx = null;
SessionFactory sf = buildSessionFactory("jdbc:mysql://localhost:3306", "admin", "password");
// ERROR Specified JDBC Driver com.mysql.jdbc.Driver could not be loaded WHY ???
session = sf.openSession();
System.out.println(session);
}
private static SessionFactory buildSessionFactory(String myUrl, String myUser, String myPass) {
Configuration configuration = new Configuration();
configuration.configure();
configuration.setProperty("hibernate.connection.url", myUrl);
configuration.setProperty("hibernate.connection.username", myUser);
configuration.setProperty("hibernate.connection.password", myPass);
configuration.setProperty("hibernate.connection.driver_class", "com.mysql.jdbc.Driver");
configuration.setProperty("hibernate.hbm2ddl.auto", "create-drop");
ServiceRegistry serviceRegistry = new ServiceRegistryBuilder().applySettings(configuration.getProperties()).buildServiceRegistry();
return configuration.buildSessionFactory(serviceRegistry);
}
}
Two questions:
Why doesn't it work with hibernate, but works with jdbc?
How to fix it?
The answer is that the Hibernate will attempt to load the driver from the context (current thread) classloader and it doesn't have the driver. The first part works because you use the classloader that has the driver to create a connection.
The solution could be to use manipulate the context classloader. Just don't forget to clean it up when methods using the loaded driver exit.
The approach to your problem could be something like this:
Idea is to have your own classloader and use that ClassLoader class of yours before initializing your Hibernate SessionFactory
Like this:
Thread.currentThread().setContextClassLoader(myOwnClassLoader);
Though this is not one of the best solutions to address your problem, that is how it is. Though this is an incomplete discussion, it is still useful enough to give you pointers to proceed.
Hope this helps!!!

Permanent database with H2

I want my H2 database to be stored into a file, so that once I close the application and open it again, all the data that was previously written to the database is still there, but for some reason, at the moment whenever I start the application, the database is completely empty. Any suggestions?
#Bean
public DataSource dataSource() {
File f = new File(".");
JdbcDataSource ds = new JdbcDataSource();
ds.setURL("jdbc:h2:file:" + f.getAbsolutePath() + "/db/aurinko");
ds.setUser("");
ds.setPassword("");
return ds;
}
private Properties getHibernateProperties() {
Properties prop = new Properties();
prop.put("hibernate.format_sql", "true");
prop.put("hibernate.show_sql", "false");
prop.put("hibernate.dialect", "org.hibernate.dialect.H2Dialect");
prop.put("hibernate.hbm2ddl.auto", "update");
return prop;
}
#Bean
public SessionFactory sessionFactory() throws IOException {
LocalSessionFactoryBuilder builder = new LocalSessionFactoryBuilder(dataSource());
builder.scanPackages("io.aurinko.server.jpa").addProperties(getHibernateProperties());
SessionFactory result = builder.buildSessionFactory();
return result;
}
I was using spring-boot. Turns out that spring-boot generates its own H2 database. That means that I had two separate databases, one of which I was trying to use and the second one (only the in-memory one) that I was actually using.
May be try setting auto commit to true in the config/ property file. It may work

How to get database configurations using data source object in java

I'm stuck in a issue related to data source objects in java.
I have set data source connection parameters in data source object(org.apache.tomcat.jdbc.pool.DataSource). I wants to get those parameters from data source object before i call getConnection method log meaningful debug info inside catch if it catches exception.
Following is the code so far i have tried. I can get all the connection parameters from metadata as follows[ex:- connection.getMetaData().getURL()], but i wants to catch exception and log url,password,username as a log if getConnection() throws exception. Therefore, i need to get those information from data source object before it tries to creates db connection.
try {
// try to get the lookup name. If error empty string will be returned
jndiLookupName = connectionProperties.getProperty(RDBMSConstants.PROP_JNDI_LOOKUP_NAME);
datasource = InitialContext.doLookup(jndiLookupName);
connection = datasource.getConnection(); // WHEN THIS THROWS EXCEPTION...
logger.info(connection.getMetaData().getURL()); // these won't work since exception already thrown.
logger.info(connection.getMetaData().getUserName());
logger.info(connection.getMetaData().getDriverName());
logger.info(connection.getMetaData().getDriverVersion());
isConnected = true; // if no errors
logger.info("JDBC connection established with jndi config " + jndiLookupName);
} catch (SQLException e) {
//...I WANT ALL CONNECTION PARAMETERS (URL,PASSWORD,USERNAME) HERE
throw new SQLException("Connecting to database failed with jndi lookup", e);
}
When i remote debug i get data source object as follows..
org.apache.tomcat.jdbc.pool.DataSource#d47feb3{ConnectionPool[defaultAutoCommit=null; defaultReadOnly=null; defaultTransactionIsolation=-1; defaultCatalog=null; driverClassName=com.mysql.jdbc.Driver; maxActive=100; maxIdle=8; minIdle=0; initialSize=0; maxWait=30000; testOnBorrow=false; testOnReturn=false; timeBetweenEvictionRunsMillis=5000; numTestsPerEvictionRun=0; minEvictableIdleTimeMillis=60000; testWhileIdle=false; testOnConnect=false; password=********; url=jdbc:mysql://localhost/wso2_mb_1; username=a; validationQuery=null; validationQueryTimeout=-1; validatorClassName=null; validationInterval=30000; accessToUnderlyingConnectionAllowed=true; removeAbandoned=false; removeAbandonedTimeout=60; logAbandoned=false; connectionProperties=null; initSQL=null; jdbcInterceptors=ConnectionState;StatementFinalizer;org.wso2.carbon.ndatasource.rdbms.ConnectionRollbackOnReturnInterceptor;; jmxEnabled=true; fairQueue=true; useEquals=true; abandonWhenPercentageFull=0; maxAge=0; useLock=false; dataSource=null; dataSourceJNDI=null; suspectTimeout=0; alternateUsernameAllowed=false; commitOnReturn=false; rollbackOnReturn=false; useDisposableConnectionFacade=true; logValidationErrors=false; propagateInterruptState=false; ignoreExceptionOnPreLoad=false; }
I can see all the url, username and password parameters are there but i can not get those. Is there a way to get these values from data source object.
Cast to the concrete implementation of the DataSource - the tomcat pooled datasource provides access to username, url etc. (see DataSource for details):
if (dataSource instanceof org.apache.tomcat.jdbc.pool.DataSource) {
org.apache.tomcat.jdbc.pool.DataSource tcDataSource = (org.apache.tomcat.jdbc.pool.DataSource)dataSource;
logger.info(tcDataSource.getUrl());
logger.info(tcDataSource.getUsername());
...
}
Invoke .getPoolProperties to get a Properties object
DataSource ds = new DataSource();
....
PoolConfiguration config = ds.getPoolProperties();
Properties dbProperties = config.getDbProperties();
The dbProperties extends the Hashtable<Object,Object> class so you can get an entrySet with all the properties
I don't think you could do that since DataSource is just an abstraction and implemented by a driver vendor, just a connection factory. You should try to get the parameters elsewhere like a config property file or such

Method Hibernate.createBlob() is deprecated from Hibernate 4.0.1 and moved to Hibernate.getLobCreator(Session session).createBlob()

Method Hibernate.createBlob() is deprecated from Hibernate 4.0.1 and moved to Hibernate.getLobCreator(Session session).createBlob(). Any solution what should I pass inside method getLobCreator(Session session), i.e in place of Session, Or any other solution showing how to retrieve and save an image into DB using Spring and Hibernate.
According to this easy tutorial,
Session Object
A Session is used to get a physical connection with a database. The Session object is lightweight and designed to be
instantiated each time an interaction is needed with the database.
Persistent objects are saved and retrieved through a Session object.
The session objects should not be kept open for a long time because
they are not usually thread safe and they should be created and
destroyed them as needed.
In Hibernate 4.0+ you can get Session object from a SessionFactory. Let's write a handy class for this task.
package your.company.util;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.service.ServiceRegistryBuilder;
public class HibernateUtil {
private static final SessionFactory sessionFactory;
static {
try {
// Create the SessionFactory from hibernate.cfg.xml
Configuration configuration = new Configuration().configure();
ServiceRegistry registry = new ServiceRegistryBuilder()
.applySettings(configuration.getProperties())
.buildServiceRegistry();
sessionFactory = configuration.buildSessionFactory(registry);
} catch (Throwable ex) {
// Make sure you log the exception, as it might be swallowed
System.err.println("Initial SessionFactory creation failed." + ex);
throw new ExceptionInInitializerError(ex);
}
}
public static SessionFactory getSessionFactory() {
return sessionFactory;
}
public static void shutdown() {
// Close caches and connection pools
getSessionFactory().close();
}
}
Then:
Session session = HibernateUtil.getSessionFactory().openSession();
session.beginTransaction();
byte[] bFile = /* load image into byte array */;
Blob image = Hibernate.getLobCreator(session).createBlob(bFile);
/* ? Your actions with Blob ? */
session.getTransaction().commit();
Let me know, if it works.
Or (assume Employee is a POJO with a field #Lob private byte[] photo;, binded to the corresponding table):
Session session = HibernateUtil.getSessionFactory().openSession();
session.beginTransaction();
byte[] bFile = /* load image into byte array */;
Employee employee = new Employee();
employee.setPhoto(bFile);
session.save(employee);
session.getTransaction().commit();
Info from mkyong.com. Here you can find the full example of how to save image into database. And the example of how to retrieve image.
Note: For Hibernate 4.3+ your code inside try block slightly changes. Because class ServiceRegistryBuilder is replaced by StandardServiceRegistryBuilder.
Configuration configuration = new Configuration().configure();
StandardServiceRegistryBuilder builder = new StandardServiceRegistryBuilder()
.applySettings(configuration.getProperties());
SessionFactory factory = configuration.buildSessionFactory(builder.build());

Categories