I have a web application that is working fine under the following environment
- GWT 2.4.0
- RestEasy 2.3.2.Final JAX-RS & JAXB
- Hibernate JPA 2.0 (hibernate-entitymanager + hibernate-validator) 4.2.0.Final
- MySQL 5.5.22 at localhost (Ubuntu 12.04)
- VMware 2.6 tomcat server
The application is working successfully using JAX-RS, JAXB, Jackson JSON provider, Hibernate JPA annotations all mixed together into the same DTO.
I am trying to port it to GAE CloudSQL. I am encountering MySQL access errors. I had to change the ORM from Hibernate to EclipseLink 2.3.2.
Reminder:
I respectfully request answerers not to hypothesize on possibility of mistakes in my code rather than solving the question at hand - how to port my Hibernate-based JPA to EclipseLink. Unless you believe that my set-up or code suitable for Hibernate requires changes to work with GAE CloudSQL. Reason being, the application is working fine under Hibernate.
Please do not provide instruction on how to make Hibernate work with GAE CloudSQL unless it involves Hibernate JPA 2.0. I realise there is an example on the internet on how to use Hibernate with CloudSQL but without JPA.
It would be extremely helpful if you have information on how to make DataNucleus JPA 2.0 work with GAE CloudSQL. I could not make it work, which is the reason why I am using EclipseLink.
Also, the MySQL datasource user and password is able to access the database either thro Eclipse datasource explorer or SQL Explorer or SQL Squirrel Client. So, no problem with the user/password. Unless you believe I need to make modifications to MqSQL user or host setup.
I have already included an additional line in mysql.db table to include host localhost.localdomain.
I have already modified my launch/debug config to -Drdbms.url=jdbc:mysql://localhost:3306/Site?user=site&password=random&useInformationSchema=true&useUnicode=true&characterEncoding=UTF8&useServerPrepStmts=true, as instructed by "Using a Local MySQL Instance During Development" in http://developers.google.com/cloud-sql/docs/developers_guide_java.
Your suggestion for resolution must involve JPA 2.0 not 1.0.
I am not accessing my CloudSQL account but localhost MySQL database running on Ubuntu 12.04. I have not tried accessing my CloudSQL database using this application (yet).
May be, I need more lines in my persistence.xml? May be my EMF setup needs to be modified? May be, GAE requires a different sequence of obtaining EMF than Hibernate? Perhaps, I need to disable DataNucleus?
Please help and advise. Thank you very much.
The error stack indicates java.security.AccessControlException: access denied ("java.net.SocketPermission" "localhost" "resolve"):
Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException: Could not create connection to database server.
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:525)
at com.google.appengine.tools.development.agent.runtime.Runtime.newInstance_(Runtime.java:126)
at com.google.appengine.tools.development.agent.runtime.Runtime.newInstance(Runtime.java:134)
at com.mysql.jdbc.Util.handleNewInstance(Util.java:411)
at com.mysql.jdbc.Util.getInstance(Util.java:386)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1013)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:987)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:982)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:927)
at com.mysql.jdbc.ConnectionImpl.connectOneTryOnly(ConnectionImpl.java:2411)
at com.mysql.jdbc.ConnectionImpl.createNewIO(ConnectionImpl.java:2153)
at com.mysql.jdbc.ConnectionImpl.<init>(ConnectionImpl.java:792)
at com.mysql.jdbc.JDBC4Connection.<init>(JDBC4Connection.java:47)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:525)
at com.google.appengine.tools.development.agent.runtime.Runtime.newInstance_(Runtime.java:126)
at com.google.appengine.tools.development.agent.runtime.Runtime.newInstance(Runtime.java:134)
at com.mysql.jdbc.Util.handleNewInstance(Util.java:411)
at com.mysql.jdbc.ConnectionImpl.getInstance(ConnectionImpl.java:381)
at com.mysql.jdbc.NonRegisteringDriver.connect(NonRegisteringDriver.java:305)
at java.sql.DriverManager.getConnection(DriverManager.java:579)
at java.sql.DriverManager.getConnection(DriverManager.java:190)
at org.eclipse.persistence.sessions.DefaultConnector.connect(DefaultConnector.java:98)
... 55 more
Caused by: java.security.AccessControlException: access denied ("java.net.SocketPermission" "localhost" "resolve")
at java.security.AccessControlContext.checkPermission(AccessControlContext.java:366)
at java.security.AccessController.checkPermission(AccessController.java:555)
at java.lang.SecurityManager.checkPermission(SecurityManager.java:549)
at com.google.appengine.tools.development.DevAppServerFactory$CustomSecurityManager.checkPermission(DevAppServerFactory.java:252)
at java.lang.SecurityManager.checkConnect(SecurityManager.java:1048)
at java.net.InetAddress.getAllByName0(InetAddress.java:1203)
at java.net.InetAddress.getAllByName(InetAddress.java:1127)
at java.net.InetAddress.getAllByName(InetAddress.java:1063)
at com.mysql.jdbc.StandardSocketFactory.connect(StandardSocketFactory.java:247)
at com.mysql.jdbc.MysqlIO.<init>(MysqlIO.java:294)
at com.mysql.jdbc.ConnectionImpl.coreConnect(ConnectionImpl.java:2332)
at com.mysql.jdbc.ConnectionImpl.connectOneTryOnly(ConnectionImpl.java:2369)
persistence.xml:
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
version="1.0">
<persistence-unit name="Site" transaction-type="RESOURCE_LOCAL">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<class>org.blessedgeek.site.jaxrs.dto.Node</class>
<properties>
<property name="javax.persistence.jdbc.user" value="site" />
<property name="javax.persistence.jdbc.password" value="random" />
<property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/Site" />
<property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"></property>
</properties>
</persistence-unit>
</persistence>
maven dependencies
<properties>
<resteasy.version>2.3.2.Final</resteasy.version>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.10</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.google.gwt</groupId>
<artifactId>gwt-user</artifactId>
<version>2.4.0</version>
</dependency>
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>1.0.0.GA</version>
</dependency>
<dependency>
<groupId>com.smartgwt</groupId>
<artifactId>smartgwt</artifactId>
<version>3.0</version>
</dependency>
<dependency>
<groupId>com.smartgwt</groupId>
<artifactId>smartgwt-skins</artifactId>
<version>3.0</version>
</dependency>
<dependency>
<groupId>com.googlecode.mvp4g</groupId>
<artifactId>mvp4g</artifactId>
<version>1.4.0</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.18</version>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-jaxrs</artifactId>
<version>${resteasy.version}</version>
<type>jar</type>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-jaxb-provider</artifactId>
<version>${resteasy.version}</version>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-jackson-provider</artifactId>
<version>${resteasy.version}</version>
</dependency>
</dependencies>
appengine-web.xml
<?xml version="1.0" encoding="utf-8"?>
<appengine-web-app xmlns="http://appengine.google.com/ns/1.0">
<application></application>
<version>1</version>
<threadsafe>true</threadsafe>
<!-- Configure serving/caching of GWT files -->
<static-files>
<include path="**" />
<include path="**.nocache.*" expiration="0s" />
<include path="**.cache.*" expiration="365d" />
<exclude path="**.gwt.rpc" />
</static-files>
<system-properties>
<property name="java.util.logging.config.file" value="WEB-INF/logging.properties"/>
</system-properties>
<sessions-enabled>true</sessions-enabled>
<async-session-persistence enabled="true" />
</appengine-web-app>
web.xml
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<display-name>Blessed Geek Site</display-name>
<!-- Auto scan REST service -->
<context-param>
<param-name>resteasy.scan</param-name>
<param-value>true</param-value>
</context-param>
<!-- this need same with resteasy servlet url-pattern -->
<context-param>
<param-name>resteasy.servlet.mapping.prefix</param-name>
<param-value>/site</param-value>
</context-param>
<listener>
<listener-class>
org.jboss.resteasy.plugins.server.servlet.ResteasyBootstrap
</listener-class>
</listener>
<servlet>
<servlet-name>resteasy-servlet</servlet-name>
<description>JAX-RS Tools Generated - Do not modify</description>
<servlet-class>org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>resteasy-servlet</servlet-name>
<url-pattern>/site/*</url-pattern>
</servlet-mapping>
</web-app>
Example DTO class
@Entity
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement (name="node")
@XmlType(propOrder = { "id", "name", "description", "iconURL", "parentID", "active", "type"})
public class Node
implements Serializable{
public enum Type{
VIEW, ROOTNode, FOLDER, LEAF
}
@XmlAttribute
@Id
@GeneratedValue
private Long id;
@XmlAttribute
private String name;
@XmlAttribute
private String description;
@XmlAttribute
private String iconURL;
@XmlAttribute
private long parentID;
@XmlAttribute
private boolean active;
@XmlAttribute
@Enumerated(EnumType.STRING)
private Type type;
public Node() {
super();
}
public Node(String name, String description) {
super();
this.name = name;
this.description = description;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getIconURL() {
return iconURL;
}
public void setIconURL(String iconURL) {
this.iconURL = iconURL;
}
public long getParentID() {
return parentID;
}
public void setParentID(long parentID) {
this.parentID = parentID;
}
public boolean isActive() {
return active;
}
public void setActive(boolean active) {
this.active = active;
}
public Type getType() {
return type;
}
public void setType(Type type) {
this.type = type;
}
}
Update 2012/05/16:
I have also replaced the jdbc driver to com.google.appengine.api.rdbms.AppEngineDriver in persistence.xml. Still encountering the same access control exception.