I am attempting to persist data to a PostgreSQL-database via Hibernate, have put in my user/pass, checked that it's working, made a db and some tables.
When I compile, I get an error
org.postgresql.util.PSQLException: The server
requested password-based authentication, but no password was provided.
I'm using IntelliJ Ultimate 2017.1 and have tried using both the supplied pg driver and 42.00 as external library.
I've had it working in previous versions, but never seen this one before. Must admit I'm not very good at this.
Basically, my defined password does not get correctly passed on to the server. It seems like it recognized my username. I've temporarily evaded this problem by modifying my pg_hba.conf file to trust local connections without password, but I am going to persist the data on an online server, so I'm gonna need a better fix.
The driver has a standard URL template that looks like this:
jdbc:postgresql:{database::postgres}[\?<&,user={user:param},password={password:param},{:identifier}={:param}>]
Here is my hibernate.cfg.xml
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property name="connection.url">jdbc:postgresql://localhost:5432/gigahertz</property>
<property name="connection.driver_class">org.postgresql.Driver</property>
<mapping class="no.hvl.dat101.gigahertz.ReservationJPA"/>
<!-- <property name="connection.username"/> -->
<!-- <property name="connection.password"/> -->
<!-- DB schema will be updated if needed -->
<!-- <property name="hbm2ddl.auto">update</property> -->
</session-factory>
Here is my generated Main-class
package no.hvl.dat101.gigahertz;
import org.hibernate.HibernateException;
import org.hibernate.Metamodel;
import org.hibernate.query.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import javax.persistence.metamodel.EntityType;
import java.util.Map;
/**
*/
public class Main {
private static final SessionFactory ourSessionFactory;
static {
try {
Configuration configuration = new Configuration();
configuration.configure();
ourSessionFactory = configuration.buildSessionFactory();
} catch (Throwable ex) {
throw new ExceptionInInitializerError(ex);
}
}
public static Session getSession() throws HibernateException {
return ourSessionFactory.openSession();
}
public static void main(final String[] args) throws Exception {
final Session session = getSession();
try {
System.out.println("querying all the managed entities...");
final Metamodel metamodel = session.getSessionFactory().getMetamodel();
for (EntityType<?> entityType : metamodel.getEntities()) {
final String entityName = entityType.getName();
final Query query = session.createQuery("from " + entityName);
System.out.println("executing: " + query.getQueryString());
for (Object o : query.list()) {
System.out.println(" " + o);
}
}
} finally {
session.close();
}
}
}
Any advice appreciated!
The solution to this was to add the parameters in the try block in main in the form configuration.setProperty("hibernate.connection.username","username) etc.
For some reason, the login details were not passed correctly by IntelliJ to the server.
Related
I have a simple console application built using Hibernate. It throws an exception when I run it, and I don't know what the problem is.
My code is:
import org.hibernate.SessionFactory;
import org.hibernate.cfg.AnnotationConfiguration;
import org.hibernate.classic.Session;
import org.hibernate.tool.hbm2ddl.SchemaExport;
public class TestEmployee {
public static void main(String[] args) {
AnnotationConfiguration config = new AnnotationConfiguration();
config.addAnnotatedClass(Employee.class);
config.configure("hibernate.cfg.xml");
new SchemaExport(config).create(true, true);
SessionFactory factory = config.buildSessionFactory();
Session session = factory.getCurrentSession();
session.beginTransaction();
Employee tom = new Employee();
mehdi.setEmpId(100);
mehdi.setEmpName("Tom Hani");
session.save(mehdi);
session.getTransaction().commit();
}
}
The exception is:
Exception in thread "main" org.hibernate.HibernateException: No CurrentSessionContext configured!
at org.hibernate.impl.SessionFactoryImpl.getCurrentSession(SessionFactoryImpl.java:685)
at com.Hibernate.chapter1.TestEmployee.main(TestEmployee.java:20)
I suspect your Hibernate configuration is not proper for current session.
Either you are missing hibernate.current_session_context config or using below property in your hibernate configuration
<property name="hibernate.current_session_context_class">org.hibernate.context.ThreadLocalSessionContext</property>
instate please use below property
<property name="hibernate.current_session_context_class">thread</property>
For more information on Hibernate current session please visit this link.
EDIT: Apparently I had to make an AMP and map it to Alfresco.war. But now I can't access the code I wrote, so I guess I'll have to use Webscripts and the like. Can someone provide an example of how to add a document to the Alfresco Repository with a Java backed webscript?
ORIGINAL QUESTION:
I've searched google-wide for a way to add a document to the Alfresco Repository with Java code. But I was not able to find a way that would work. I know how I can add a document to the Repository: use the NodeService. But the problem is that I cannot get an instance of the NodeService. I've tried to inject it with #Autowired, I've tried using a bean and I've tried using an ApplicationContext. None of the ways worked...
Way #1:
Injection in a class:
#Autowired
NodeService nodeService
Way #2:
In service-context.xml:
<bean id="somerandombeanname" class="management.FileManager" >
<property name="moduleId" value="${project.artifactId}" />
<property name="serviceRegistry" ref="ServiceRegistry" />
<property name="nodeService" ref="NodeService" />
<property name="transactionService" ref="TransactionService" />
<property name="contentService" ref="ContentService" />
</bean>
In the class I added a getter and setter for all the services and the serviceRegistry:
private NodeService nodeService;
public void setNodeService(NodeService nodeService) {
this.nodeService = nodeService;
}
Way #3:
appContext = new ClassPathXmlApplicationContext("classpath:alfresco/application-context.xml");
serviceRegistry = (ServiceRegistry) appContext.getBean(ServiceRegistry.SERVICE_REGISTRY);
nodeService = serviceRegistry.getNodeService();
Ways #1 and #2 gave me a NullPointerException simply stating the NodeService is null. Way #3 gave a mile long StackTrace because of an AlfrescoRuntimeException because it failed to initialize a keystore:
Exception in thread "main" java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.eclipse.jdt.internal.jarinjarloader.JarRsrcLoader.main(JarRsrcLoader.java:58)
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'ssl.keyStore' defined in class path resource [alfresco/encryption-context.xml]: Invocation of init method failed; nested exception is org.alfresco.error.AlfrescoRuntimeException: 04180000 Failed to initialize keystore:
Location: E:/Alfresco/alf_data/keystore/ssl.keystore
Provider: null
Type: JCEKS
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1513)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:521)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:458)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:293)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:223)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:290)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:191)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:633)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:932)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:479)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:139)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:83)
at management.FileManager.<init>(FileManager.java:36)
at simple.start.main(start.java:25)
... 5 more
Caused by: org.alfresco.error.AlfrescoRuntimeException: 04180000 Failed to initialize keystore:
Location: E:/Alfresco/alf_data/keystore/ssl.keystore
Provider: null
Type: JCEKS
at org.alfresco.encryption.AlfrescoKeyStoreImpl.loadKeyStore(AlfrescoKeyStoreImpl.java:566)
at org.alfresco.encryption.AlfrescoKeyStoreImpl.safeInit(AlfrescoKeyStoreImpl.java:537)
at org.alfresco.encryption.AlfrescoKeyStoreImpl.init(AlfrescoKeyStoreImpl.java:122)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeCustomInitMethod(AbstractAutowireCapableBeanFactory.java:1639)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1580)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1510)
... 18 more
Caused by: java.lang.IllegalArgumentException: name
at sun.misc.URLClassPath$Loader.findResource(URLClassPath.java:494)
at sun.misc.URLClassPath.findResource(URLClassPath.java:176)
at java.net.URLClassLoader$2.run(URLClassLoader.java:551)
at java.net.URLClassLoader$2.run(URLClassLoader.java:549)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findResource(URLClassLoader.java:548)
at java.lang.ClassLoader.getResource(ClassLoader.java:1147)
at org.springframework.core.io.ClassPathResource.resolveURL(ClassPathResource.java:147)
at org.springframework.core.io.ClassPathResource.exists(ClassPathResource.java:135)
at org.alfresco.encryption.SpringKeyResourceLoader.getSafeInputStream(SpringKeyResourceLoader.java:67)
at org.alfresco.encryption.SpringKeyResourceLoader.loadKeyMetaData(SpringKeyResourceLoader.java:133)
at org.alfresco.encryption.AlfrescoKeyStoreImpl$KeyInfoManager.loadKeyMetaData(AlfrescoKeyStoreImpl.java:1016)
at org.alfresco.encryption.AlfrescoKeyStoreImpl$KeyInfoManager.<init>(AlfrescoKeyStoreImpl.java:998)
at org.alfresco.encryption.AlfrescoKeyStoreImpl.getKeyInfoManager(AlfrescoKeyStoreImpl.java:395)
at org.alfresco.encryption.AlfrescoKeyStoreImpl.loadKeyStore(AlfrescoKeyStoreImpl.java:560)
... 27 more
Yes, the keystore exists and yes I have regenerated a new keystore.
I'm using Alfresco 5.0.1 and I'm working on the Repository side (not Share).
#Autowired
NodeService nodeService
Will not work in alfresco
You need to inject it with proper setter method.
Your bean should be like below.
<bean id="somerandombeanname" class="management.FileManager" >
<property name="moduleId" value="${project.artifactId}" />
<property name="serviceRegistry" ref="ServiceRegistry" />
<property name="nodeService" ref="NodeService" />
<property name="transactionService" ref="TransactionService" />
<property name="contentService" ref="ContentService" />
</bean>
Your java class should contain following for injecting nodeService.
private NodeService nodeService;
public void setNodeService(NodeService nodeService) {
this.nodeService = nodeService;
}
Luckily I have code for file upload thorugh JAVA backed webscript. Hope this help you too.To create java backed webscript see this
Create one class named CustomFileUpload.java and put following content
package com.upload;
import org.springframework.extensions.webscripts.Cache;
import org.springframework.extensions.webscripts.DeclarativeWebScript;
import org.springframework.extensions.webscripts.Status;
import org.springframework.extensions.webscripts.WebScriptRequest;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.methods.multipart.FilePart;
import org.apache.commons.httpclient.methods.multipart.MultipartRequestEntity;
import org.apache.commons.httpclient.methods.multipart.Part;
import org.apache.commons.httpclient.methods.multipart.StringPart;
import org.apache.commons.io.IOUtils;
import org.json.JSONException;
import org.json.JSONObject;
public class CustomFileUpload extends DeclarativeWebScript {
private final String UPLOAD_FILE_PATH = "C:\\Users\\Test\\Desktop\\test.txt";
private int statusCode;
protected Map<String, Object> executeImpl(WebScriptRequest arg0, Status status, Cache cache) {
Map<String, Object> model = new HashMap<String, Object>();
try {
String URL = "http://localhost:8080/alfresco/service/upload/fileupload?alf_ticket=" +getAlfticket();
File file = new File(UPLOAD_FILE_PATH);
String filetype = "text/plain";
String filename = file.getName();
HttpClient client = new HttpClient();
PostMethod post = new PostMethod(URL);
Part[] parts = {
new FilePart("filedata", filename, file, filetype, null),
new StringPart("filename", filename),
new StringPart("description", "This is test description"),
new StringPart("destination", "workspace://SpacesStore/bb424b1d-0418-4954-8591-b8c807264df0")
};
post.setRequestEntity(new MultipartRequestEntity(parts, post.getParams()));
statusCode = client.executeMethod(post);
System.out.println(post.getResponseBodyAsString());
post.releaseConnection();
} catch (Exception e) {
e.printStackTrace();
}
if (statusCode == 200) {
model.put("result", "File uploaded successfully.");
return model;
} else {
model.put("result", "There was an error while uploading document.");
return model;
}
}
private static String getAlfticket() throws IOException, JSONException {
URL url = new URL("http://localhost:8080/alfresco/service/api/login?u=admin&pw=admin&format=json");
URLConnection con = url.openConnection();
InputStream in = con.getInputStream();
String encoding = con.getContentEncoding();
encoding = encoding == null ? "UTF-8" : encoding;
String json = IOUtils.toString(in, encoding);
JSONObject getData = new JSONObject(json);
return getData.getJSONObject("data").get("ticket").toString();
}
}
NOTE: In destination you can put nodeRef of folder in which you want to upload.
Than create bean in context file name it whatever you want say mycustom-context.xml and put it in ALFRESCO_HOME\tomcat\shared\classes\alfresco\extension and content
<bean id="webscript.com.upload.customupload.post" class="com.upload.CustomFileUpload" parent="webscript">
</bean>
Finally register this web script in alfresco by creating customupload.post.desc.xml. and put
<webscript>
<shortname>File Upload</shortname>
<description>Upload files to user home</description>
<url>/upload/fileupload?alf_ticket={ticket}</url>
<format default="json"/>
<authentication>user</authentication>
</webscript>
And last create view as we have declared JSON is default format so we need to create customupload.post.json.ftl
${result}
And put these both files in ALFRESCO_HOME\tomcat\shared\classes\alfresco\extension\templates\webscripts\com\upload
Now restart server and hit http://localhost:8080/alfresco/service/upload/fileupload and you will see file uploaded in folder(Whatever you have given). For Reference
Finally! This is the solution for adding a file to the Repository:
CustomFileUpload.java:
package org.example;
import org.springframework.extensions.webscripts.Cache;
import org.springframework.extensions.webscripts.DeclarativeWebScript;
import org.springframework.extensions.webscripts.Status;
import org.springframework.extensions.webscripts.WebScriptRequest;
import java.io.File;
import java.io.IOException;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.content.MimetypeMap;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.repository.ContentWriter;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.search.ResultSet;
import org.alfresco.service.cmr.search.SearchService;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
import org.apache.commons.io.FileUtils;
public class CustomFileUpload extends DeclarativeWebScript {
private final String UPLOAD_FILE_PATH = "{someRandomFile}";
private final String UPLOAD_DESTINATION = "workspace://SpacesStore/{someRandomNodeRef}";
protected ServiceRegistry serviceRegistry;
public ServiceRegistry getServiceRegistry() {
return serviceRegistry;
}
public void setServiceRegistry(ServiceRegistry serviceRegistry) {
this.serviceRegistry = serviceRegistry;
}
protected Map<String, Object> executeImpl(WebScriptRequest req, Status status, Cache cache) {
File file = new File(UPLOAD_FILE_PATH);
// NodeRef parent = getCompanyHome();
NodeRef parent = new NodeRef(UPLOAD_DESTINATION);
String name = "name of file in Repository " + System.currentTimeMillis();
Map<QName, Serializable> props = new HashMap<QName, Serializable>(1);
props.put(ContentModel.PROP_NAME, name);
// use the node service to create a new node
NodeRef node = serviceRegistry.getNodeService().createNode(
parent,
ContentModel.ASSOC_CONTAINS,
QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, name),
ContentModel.TYPE_CONTENT, props).getChildRef();
// Use the content service to set the content onto the newly created
// node
ContentWriter writer = serviceRegistry.getContentService().getWriter(node, ContentModel.PROP_CONTENT, true);
writer.setMimetype(MimetypeMap.MIMETYPE_TEXT_PLAIN);
writer.setEncoding("UTF-8");
String text = "";
try {
text = FileUtils.readFileToString(file);
} catch (IOException e) {
e.printStackTrace();
}
writer.putContent(text);
Map<String, Object> model = new HashMap<String, Object>();
if (status.getCode() == Status.STATUS_OK) {
model.put("resultRepoWS", "File \"" + file.getName() + "\" uploaded successfully to the repository. Status: " + status.getCode());
return model;
} else {
model.put("resultRepoWS", "There was an error while uploading document \"" + file.getName() + "\" - Status: " + status.getCode());
return model;
}
}
//If you want to test with CompanyHome first use this method instead of the NodeRef
#SuppressWarnings("unused")
private NodeRef getCompanyHome() {
StoreRef storeRef = new StoreRef(StoreRef.PROTOCOL_WORKSPACE, "SpacesStore");
serviceRegistry.getSearchService();
ResultSet rs = serviceRegistry.getSearchService().query(storeRef, SearchService.LANGUAGE_XPATH, "/app:company_home");
NodeRef parent = null;
try {
if (rs.length() == 0) {
throw new AlfrescoRuntimeException("Didn't find Company Home");
}
parent = rs.getNodeRef(0);
} finally {
rs.close();
}
return parent;
}
}
This java class is placed in the following folder:
{tomcat}\webapps\alfresco\WEB-INF\classes\org\example
Where org\example is the same as the package org.example. Now we have a class, now we need the configuration files as I call them:
customfileupload-context.xml
Which is located here
{tomcat}\shared\classes\alfresco\extension
You will also need these:
customfileupload.post.desc.xml
customfileupload.post.json.ftl
Which are located here
{tomcat}\shared\classes\alfresco\extension\webscripts\org\example
Noticed the folder? It's the same like the package mentioned earlier.
Contents of customfileupload-context.xml:
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE beans PUBLIC '-//SPRING//DTD BEAN 2.0//EN'
'http://www.springframework.org/dtd/spring-beans-2.0.dtd'>
<beans>
<bean id="webscript.org.example.customfileupload.post" class="org.example.CustomFileUpload" parent="webscript">
<property name="ServiceRegistry" ref="ServiceRegistry" />
</bean>
</beans>
Contents of customfileupload.post.desc.xml:
<webscript>
<shortname>File Upload</shortname>
<description>Upload files to user home</description>
<url>/upload/fileupload.json</url>
<format default="json"/>
<authentication runas="admin">guest</authentication>
<transaction>required</transaction>
</webscript>
Contents of customfileupload.post.json.ftl:
<#escape x as jsonUtils.encodeJSONString(x)> { "resultRepoWS": "${resultRepoWS}" } </#escape>
This is it. With this you'll be able to upload a file to the Repository of Alfresco with Alfresco 5.
I am trying to connect a small java application with a database using MyBatis.
XML file:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="oracle.jdbc.driver.OracleDriver"/>
<property name="url" value="jdbc:oracle:thin:#xxxx:xxxx:xxxx"/>
<property name="username" value="xxxxx"/>
<property name="password" value="xxxxx"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="xml/Mapper.xml"/>
</mappers>
</configuration>
Before, I got the session as follows
String resource = "Configuration.xml";
SqlSession session = null;
try{
Reader reader = Resources.getResourceAsReader(resource);
SqlSessionFactory sqlMapper = new SqlSessionFactoryBuilder().build(reader);
session = sqlMapper.openSession();
I want to connect to the database without the use of xml file. Any help will be appreciated.
Have you checked MyBatis 3 user guide? There is a section called "Building SqlSessionFactory
without XML". Also there is no need to use XML based mapping, you could use annotation based statement mapping and avoid XML configuration altogether.
This worked for me:
import javax.sql.DataSource;
import org.apache.ibatis.mapping.Environment;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.apache.ibatis.transaction.TransactionFactory;
import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory;
String user = "xxxxx";
String password = "xxxxx";
String databasenameURL = "jdbc:oracle:thin:#xxxx:xxxx:xxxx";
String dbDriver = "oracle.jdbc.driver.OracleDriver";
DataSource dataSource = new org.apache.ibatis.datasource.pooled.PooledDataSource(
dbDriver, databasenameURL, user, password);
TransactionFactory transactionFactory = new JdbcTransactionFactory();
Environment environment = new Environment("development",
transactionFactory, dataSource);
Configuration configuration = new Configuration(environment);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder()
.build(configuration);
Maybe its late, but for future readers.
you can parse the xml to string and modify any value you want later.:
this worked for me:
import org.apache.commons.io.IOUtils;
import org.apache.commons.io.input.CharSequenceReader;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.apache.log4j.Logger;
import java.io.IOException;
import java.io.Reader;
public class MySqlSessionFactory
{
private static Logger log = Logger.getLogger(MySqlSessionFactory.class);
private static SqlSessionFactory sessionFactory;
public static SqlSessionFactory getSqlSessionFactory()
{
return sessionFactory;
}
/**
* Initialize SqlSessionFactory instance, to be used later in all the project
*
* #return boolean if sqlSessionFactory is build
*/
public static boolean initializeMySqlSessionFactory() throws IOException
{
log.trace("Enter method initializeMySqlSessionFactory.");
String resource = "mybatis-config.xml";
boolean result;
Reader reader = null;
Reader parsedReader = null;
try
{
reader = Resources.getResourceAsReader(resource);
String parsedXMLConfig = IOUtils.toString(reader);
parsedXMLConfig = StringUtils.replace(parsedXMLConfig, "${jdbcUrl}", "databaseURL");
parsedXMLConfig = StringUtils.replace(parsedXMLConfig, "${username}", "databaseUser");
parsedXMLConfig = StringUtils.replace(parsedXMLConfig, "${password}", "databasePassword");
parsedReader = new CharSequenceReader(parsedXMLConfig);
sessionFactory = new SqlSessionFactoryBuilder().build(parsedReader);
result = true;
}
catch(IOException e)
{
result = false;
log.error("Error calling initializeMySqlSessionFactory.", e);
throw new IOException(e);
}
finally
{
if(reader != null )
{
reader.close();
}
if(parsedReader != null )
{
parsedReader.close();
}
}
log.trace("Exit method initializeMySqlSessionFactory. Method result: " + result);
return result;
}
}
also with this way, you can change any specified field you want... and pay attention to put the same placeholder in the xml file (${jdbcUrl}, ${username}, ${password})
I have hibernate which connect to database via JNDI datasource.
My purpose: registry DataSource with JNDI to test DAO layer.
Example
Hibernate config
<hibernate-configuration>
<session-factory name="MySessionFactory">
<property name="hibernate.connection.datasource">java:jdbc/MysqlMyDS</property>
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<!-- mappings .... ->
</hibernate-configuration>
Get SessionFactory in test class :
Configuration cgf = new Configuration().configure("/META-INF/hibernate.cfg.xml");
SessionFactory iceleadsSessionFactory = cgf.buildSessionFactory();
As the result:
16:04:37,753 ERROR DatasourceConnectionProvider:78 - Could not find datasource: java:jdbc/MysqlIceleadsDS
javax.naming.NoInitialContextException: Need to specify class name in environment or system property, or as an applet parameter, or in an application resource file: java.naming.factory.initial
To register JNOI I use example (http://www.roseindia.net/tutorial/java/jdbc/registeringthedatasourcewithjndi.html)
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.util.Properties;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.ConnectionPoolDataSource;
import com.mysql.jdbc.jdbc2.optional.MysqlConnectionPoolDataSource;
import com.mysql.jdbc.jdbc2.optional.MysqlDataSource;
public class RegisteringJNDIWithDataSource {
private static void startRegistry() throws RemoteException {
System.out.println(LocateRegistry.getRegistry());
LocateRegistry.createRegistry(1059);
System.out.println("RMI registry Stared.");
}
private static InitialContext createInitialContextContext()
throws NamingException {
Properties properties = new Properties();
properties.put(Context.INITIAL_CONTEXT_FACTORY,
"com.sun.jndi.rmi.registry.RegistryContextFactory");
properties.put(Context.PROVIDER_URL, "rmi://localhost:1059");
InitialContext initialContextcontext = new InitialContext(properties);
return initialContextcontext;
}
public static void main(String args[]) {
try {
startRegistry();
ConnectionPoolDataSource dataSource = new MysqlConnectionPoolDataSource();
((MysqlDataSource) dataSource).setUser("root");
((MysqlDataSource) dataSource).setPassword("root");
((MysqlDataSource) dataSource).setServerName("192.168.10.13");
((MysqlDataSource) dataSource).setPort(3306);
((MysqlDataSource) dataSource).setDatabaseName("student");
InitialContext context = createInitialContextContext();
context.rebind("Source", dataSource);
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
}
Please suggest solution. Thanks!
Your code will work, if you correctly set jndi.properties. This file should be in classpath.
here is working example:
Server:
public static void main(String[] args) throws Exception{
LocateRegistry.createRegistry(1099);
ConnectionPoolDataSource dataSource = createDataSource("root", "");
InitialContext context = createContext();
context.bind("MysqlMyDS", dataSource);
System.out.println("context created!");
}
private static InitialContext createContext() throws NamingException {
Properties env = new Properties();
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.rmi.registry.RegistryContextFactory");
env.put(Context.PROVIDER_URL, "rmi://localhost:1099");
InitialContext context = new InitialContext(env);
return context;
}
private static ConnectionPoolDataSource createDataSource(String username, String password) {
MysqlConnectionPoolDataSource dataSource = new MysqlConnectionPoolDataSource();
dataSource.setUser(username);
dataSource.setPassword(password);
dataSource.setServerName("localhost");
dataSource.setPort(3306);
dataSource.setDatabaseName("test");
return dataSource;
}
client:
hibernate.cfg.xml Note: datasource jndi name should be exactly as you set it by context.bind()
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property name="hibernate.connection.datasource">MysqlMyDS</property>
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
</session-factory>
</hibernate-configuration>
jndi.properties (if you want, you can set it in code or with -D option)
java.naming.factory.initial=com.sun.jndi.rmi.registry.RegistryContextFactory
java.naming.provider.url=rmi://localhost:1099
unit test
public class TestClient {
#Test
public void testCfg() throws Exception {
Configuration cgf = new Configuration().configure("/hibernate.cfg.xml");
cgf.buildSessionFactory();
}
}
I have a system where I need to create a new instance of SomeEntity in a concurrent context, using another entity as "monitor" as exemplified below:
//Begin transaction
Monitor monitor = (Monitor) session.load(Monitor.class, monitor.getId(), LockOptions.UPGRADE);
SomeEntity entity = createSomeEntity(monitor);
//Save entity and commit transaction
When I'm using Mysql this works perfectly with lock happening when I'm loading monitor with LockOptions.UPGRADE, but when I'm using HSQLDB the code above don't work and all threads run without lock at the database level, causing creation of many instances of SomeEntity in database.
Main Question
I need to lock a entity at database level using Hibernate and HSQLDB.
Examples
To exemplify what I need, I have created a simple project where I have a entity class called Person with two attributes (id an name) and a main program that will update the name attribute in a concurrent way for a single instance (Person#id = 1). There are 3 threads competing to update and all will be synchronized at the database level through the following instruction:
Person person = (Person) session.load(Person.class, 1L, LockOptions.UPGRADE);
Using the code above only one thread at once will update the name attribute and all other threads will wait to obtain the lock.
The lock, if happens, can be visualized in the sql code generated by Hibernate and will looks like this:
select
person0_.id as id1_0_0_,
person0_.name as name2_0_0_
from
Person person0_
where
person0_.id=? for update
or can be visualized during debug on Eclipse IDE, with a breakpoint at line where session.load(...) is called (only one thread go to the next instruction, all other threads wait).
So, remembering again: this works on Mysql but not in HSQLDB.
Attachments
package model;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
#Entity
public class Person {
#Id
#GeneratedValue
private Long id;
private String name;
public Person() {}
public Person(String name) {
this();
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
package app;
import static java.util.concurrent.Executors.newFixedThreadPool;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.TimeUnit;
import model.Person;
import org.hibernate.LockOptions;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.service.ServiceRegistryBuilder;
public class Main {
private static final SessionFactory sessionFactory = init();
public static void main(String[] args) {
populate();
changeNames("Christine", "Isabelle", "Katarina");
}
private static void changeNames(String... names) {
ExecutorService executor = newFixedThreadPool(3);
for (final String name : names) {
executor.execute(new Runnable() {
private Session session = sessionFactory.openSession();
public void run() {
Transaction transaction = null;
try {
transaction = session.beginTransaction();
// At next line I put a breakpoint to debug in Eclipse Juno SR2
Person person = (Person) session.load(Person.class, 1L, LockOptions.UPGRADE);
person.setName(name);
session.saveOrUpdate(person);
transaction.commit();
System.out.println("Name changed to " + name);
} catch (Exception e) {
if (transaction != null) {
transaction.rollback();
}
e.printStackTrace();
}
finally {
session.close();
}
}
});
}
try {
executor.shutdown();
executor.awaitTermination(1, TimeUnit.HOURS);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private static void populate() {
Session session = sessionFactory.openSession();
Transaction transaction = session.beginTransaction();
session.save(new Person("Old Name"));
transaction.commit();
session.close();
}
private static SessionFactory init() {
Configuration configuration = new Configuration().configure();
ServiceRegistry serviceRegistry = new ServiceRegistryBuilder()
.applySettings(configuration.getProperties())
.buildServiceRegistry();
return configuration.buildSessionFactory(serviceRegistry);
}
}
<?xml version="1.0"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory name="">
<mapping class="model.Person" />
</session-factory>
</hibernate-configuration>
hibernate.connection.driver_class = org.hsqldb.jdbcDriver
hibernate.dialect = org.hibernate.dialect.HSQLDialect
hibernate.connection.url = jdbc:hsqldb:mem:test;hsqldb.tx=locks;hsqldb.write_delay=false
hibernate.connection.username = sa
hibernate.connection.password =
hibernate.hbm2ddl.auto = update
#hibernate.connection.driver_class = com.mysql.jdbc.Driver
#hibernate.dialect = org.hibernate.dialect.MySQL5InnoDBDialect
#hibernate.connection.url = jdbc:mysql://localhost/test
#hibernate.connection.username = root
#hibernate.connection.password =
hibernate.show_sql = true
hibernate.format_sql = true
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>test</groupId>
<artifactId>test</artifactId>
<version>0.0.1-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>4.1.12.Final</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.18</version>
</dependency>
<dependency>
<groupId>org.hsqldb</groupId>
<artifactId>hsqldb</artifactId>
<version>2.2.9</version>
</dependency>
</dependencies>
</project>
It seems there is a hibernate HSQLDialect bug. It doesn't put a for update in the generated SQL: https://hibernate.atlassian.net/browse/HHH-7479
The bug seem to be resolved in latest beta: 4.3.0.Beta1