Tuesday, June 25, 2013

How to catch JVM crash

Problem:
 A scheduled task will invoke 3rd party library and sometimes JVM crashes and it cannot be recovered.
Solution:
 Use ProcessBuilder to invoke the possible-crash application. (It works on JRE7, not on JRE6)
public
class CrashExample {
@SuppressWarnings("restriction")
public static void main(String[] args) {
System.
out.println("Hello, I will crash!");
new sun.dc.pr.PathDasher(null);
}
}

import
java.io.IOException;
import
java.util.concurrent.Executors;
import
java.util.concurrent.TimeUnit;
 
public
class FixedTest {
public static void main(String[] args) {
Executors.newScheduledThreadPool(10).scheduleAtFixedRate(
new Runnable() {
volatile int cnt = 0;
volatile boolean is_normal;
@Override
public void run() {
cnt++;
if(is_normal||cnt<5){
System.
out.println("Running..."+cnt);
}
else{
String separator = System.getProperty(
"file.separator");
String classpath = System.getProperty(
"java.class.path");
String path = System.getProperty(
"java.home")
+ separator +
"bin" + separator + "java";
System.
out.println("path="+path);
ProcessBuilder processBuilder =
new ProcessBuilder(path, "-cp",
classpath,
CrashExample.
class.getName());
// processBuilder.inheritIO();
try {
Process process = processBuilder.start();
process.waitFor();
}
catch (IOException e) {
e.printStackTrace();
}
catch (InterruptedException e) {
e.printStackTrace();
}
System.
out.println("Running "+cnt);
is_normal = true;
}
}
}, 100, 1000, TimeUnit.
MILLISECONDS);
}
}

Thursday, June 20, 2013

interesting on JVM crash

Class CrashExample will cause JVM crashes on JDK6 and JDK7, while Crash does not crash on JDK7, although it hangs forever on JDK6.
public class CrashExample {
 public static void main(String[] args) {
  new sun.dc.pr.PathDasher(null);
 }
}

public class Crash {
 public static void main(String[] args) {
  try {
   startSecondJVM();
  } catch (Exception e) {
   e.printStackTrace();
  }
  System.out.println("Hello crash.");
 }

 public static void startSecondJVM() throws Exception {
  String separator = System.getProperty("file.separator");
  String classpath = System.getProperty("java.class.path");
  String path = System.getProperty("java.home")
                 + separator + "bin" + separator + "java";
  System.out.println("path="+path);
  ProcessBuilder processBuilder =
                 new ProcessBuilder(path, "-cp",
                 classpath,
                 CrashExample.class.getName());
//  processBuilder.inheritIO();
  Process process = processBuilder.start();
  process.waitFor();
 }
}



JPA shortage

1. DBMS_METADATA.GET_DDL returns clob instead of string, has to convert the clob to string from Java
For JDBC, getString is enough
2. Query.getResultList returns Object[] if there's more than one column, while it returns Object if there's only one column.
It's inconvenient sometimes. (For example, export the dml from the database)

Wednesday, June 12, 2013

oracle ddl extractor (based on JPA/hibernate)

While DBMS_METADATA.GET_DDL returns string in JDBC, it returns Clob in JPA/Hibernate, need to convert it to String.
The more realistic extractor would be:
import
java.io.BufferedReader;
import
java.io.BufferedWriter;
import
java.io.File;
import
java.io.FileOutputStream;
import
java.io.IOException;
import
java.io.OutputStreamWriter;
import
java.sql.Clob;
import
java.sql.SQLException;
import
java.text.DateFormat;
import
java.text.SimpleDateFormat;
import
java.util.Calendar;
import
java.util.List;
import
javax.persistence.EntityManager;
import
javax.persistence.EntityManagerFactory;
import
javax.persistence.Persistence;
public
class DDLExtractor
{
private static final String[] TYPES = {"PACKAGE","TABLE","VIEW"};
//do not include the schema prefix
private static final String NO_SCHEMA = "BEGIN DBMS_METADATA.SET_TRANSFORM_PARAM(DBMS_METADATA.SESSION_TRANSFORM,'EMIT_SCHEMA', false); END;";
//make it look pretty
private static final String PRETTY = "BEGIN DBMS_METADATA.SET_TRANSFORM_PARAM(DBMS_METADATA.SESSION_TRANSFORM,'PRETTY', true); END;";
//don't include the physical properties
private static final String NO_PHYSICAL_PROP = "BEGIN DBMS_METADATA.SET_TRANSFORM_PARAM(DBMS_METADATA.SESSION_TRANSFORM,'PHYSICAL_PROPERTIES', false); END;";
//don't include the segment attributes
private static final String NO_SEGMENT_PROP = "BEGIN DBMS_METADATA.SET_TRANSFORM_PARAM(DBMS_METADATA.SESSION_TRANSFORM,'SEGMENT_ATTRIBUTES', false); END;";
//include a sql terminator for each statement
private static final String SQL_TERMINATOR = "BEGIN DBMS_METADATA.SET_TRANSFORM_PARAM(DBMS_METADATA.SESSION_TRANSFORM,'SQLTERMINATOR', true); END;";
private static final String ENV = "DIT2";
private static final DateFormat SDF = new SimpleDateFormat("yyyyMMdd");
public static void main( String[] args ) throws IOException, SQLException
{
long start = System.currentTimeMillis();
EntityManagerFactory emf = Persistence.createEntityManagerFactory(
ENV);
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
em.createNativeQuery(
NO_SCHEMA).executeUpdate();
em.createNativeQuery(
PRETTY).executeUpdate();
em.createNativeQuery(
NO_PHYSICAL_PROP).executeUpdate();
em.createNativeQuery(
NO_SEGMENT_PROP).executeUpdate();
em.createNativeQuery(
SQL_TERMINATOR).executeUpdate();
for(String type:TYPES){
createDDL(em,type);
}
em.getTransaction().commit();
em.close();
long end = System.currentTimeMillis();
System.
out.printf("Done. Spent %d secs.", (end - start) / 1000);
}
@SuppressWarnings("unchecked")
private static void createDDL(EntityManager em,String type) throws SQLException, IOException{
String sql =
"select object_name from user_objects where object_type = '"+type.toUpperCase()+"' order by 1";
List<String> objectNameList = (List<String>)em.createNativeQuery(sql).getResultList();
for(String objectName:objectNameList){
if(type.equalsIgnoreCase("PACKAGE")){
sql =
"select DBMS_METADATA.GET_DDL('PACKAGE_SPEC','"+objectName+"') from DUAL";
export(em,
"PACKAGE_SPEC",objectName);
export(em,
"PACKAGE_BODY",objectName);
}
else{
export(em,type,objectName);
}
}
}
private static void export(EntityManager em,String type,String objectName) throws IOException{
String sql =
"select DBMS_METADATA.GET_DDL('"+type.toUpperCase()+"','"+objectName+"') from DUAL";
Clob clob = (Clob)em.createNativeQuery(sql).getSingleResult();
String ddl = clobToString(clob);
File file = getFile(type,objectName);
write(file,ddl);
}
private static File getFile(String type,String objectName){
String folder =
"";
String fileName =
"";
if(type.equalsIgnoreCase("PACKAGE_SPEC")){
folder =
"package";
fileName =
"pks."+objectName.toLowerCase()+".sql";
}
else if(type.equalsIgnoreCase("PACKAGE_BODY")){
folder =
"package";
fileName =
"pkb."+objectName.toLowerCase()+".sql";
}
else if(type.equalsIgnoreCase("TABLE")){
folder =
"table";
fileName = objectName.toLowerCase()+
".ddl";
}
else if(type.equalsIgnoreCase("VIEW")){
folder =
"view";
fileName = objectName.toLowerCase()+
".ddl";
}
File parent =
new File(ENV+"_"+SDF.format(Calendar.getInstance().getTime()),folder);
if(!parent.exists()){
parent.mkdirs();
}
return new File(parent,fileName);
}
public static void write(File file,String content) throws IOException{
BufferedWriter writer =
new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file)));
writer.append(content);
writer.newLine();
writer.close();
}
public static String clobToString(Clob clob){
StringBuffer sb =
new StringBuffer();
if (clob == null) {
return sb.toString();
}
String line;
try {
BufferedReader br =
new BufferedReader(clob.getCharacterStream());
while ((line = br.readLine()) != null) {
sb.append(line).append(
"\r\n");
}
}
catch (Exception e) {
e.printStackTrace();
}
return sb.toString();
}
}

Tuesday, June 11, 2013

Hibernate note

Hibernate note (4.2.2)
1. Download hibernate-release-4.2.2.Final and hibernate-orm-master.zip (source code)
2. Download hibernate-tutorials.zip and import into Eclipse
3. Run NativeApiIllustrationTest
4. Update hibernate.cfg.xml to based on oracle
5. Update NativeApiIllustrationTest to not use deprecated method:
  Configuration config = new Configuration().configure();//invoke configure to use hibernate.cfg.xml
  serviceRegistry = new ServiceRegistryBuilder().applySettings(config.getProperties()).buildServiceRegistry();
        sessionFactory = config.buildSessionFactory(serviceRegistry);
6. Remove property hbm2ddl.auto to keep the table
7. Remove Event.hbm.xml to use annotation
8. set Id's column name to EVENT_ID
9. Remove setId from Event to watch the error
10.JPA needs to put hibernate-entitymanager-4.2.2.Final on classpath, or it cannot find the persistence provider. (name does not matter if only it's matched)
11.Enver example will create table EVENTS,EVENTS_AUD,REVINFO and sequence hibernate_sequence
Hibernate may not be the best solution for data-centric applications that only use stored-procedures to implement the business logic in the database,
it is most useful with object-oriented domain models and business logic in the Java-based middle-tier.
The Hibernate Query Language (HQL) and Java Persistence Query Language (JPQL) are both object model focused query languages similar in nature to SQL. JPQL is a heavily-inspired-by subset of HQL. A JPQL query is always a valid HQL query, the reverse is not true however.
You may also express queries in the native SQL dialect of your database. This is useful if you want to utilize database specific features such as query hints or the CONNECT BY option in Oracle. It also provides a clean migration path from a direct SQL/JDBC based application to Hibernate/JPA.
Problem:
Difficult to get the connection from EntityManger. JPA does not define the interface.
The method to get it under hibernate 3,4 and JPA1,2 are different:
http://www.bigdev.org/2012/02/getting-jdbc-sql-connection-in-jpa-with-hibernate/

 

JPA example to backup the packages/tables of oracle database

I performed the backup task through JDBC originally, however, found it's very easy to switch to JPA.
It's impressed that it's very easy to use JPA2/Hibernate to backup database or generate the package files.
JPA2/Hibernate only brings a minor performance impact (can be ignored). It's much easier to program and the program is more elegant.
The cost is to 1) introduce additional jars 2) study JPA/Hibernate


To run the example, need persistence.xml and *.jar
import
java.io.BufferedWriter;
import
java.io.FileOutputStream;
import
java.io.IOException;
import
java.io.OutputStreamWriter;
import
java.util.List;
import
javax.persistence.EntityManager;
import
javax.persistence.EntityManagerFactory;
import
javax.persistence.Persistence;
public
class PackageFilesGenerator
{
//do not include the schema prefix
private static final String NO_SCHEMA = "BEGIN DBMS_METADATA.SET_TRANSFORM_PARAM(DBMS_METADATA.SESSION_TRANSFORM,'EMIT_SCHEMA', false); END;";
//make it look pretty
private static final String PRETTY = "BEGIN DBMS_METADATA.SET_TRANSFORM_PARAM(DBMS_METADATA.SESSION_TRANSFORM,'PRETTY', true); END;";
//don't include the physical properties
private static final String NO_PHYSICAL_PROP = "BEGIN DBMS_METADATA.SET_TRANSFORM_PARAM(DBMS_METADATA.SESSION_TRANSFORM,'PHYSICAL_PROPERTIES', false); END;";
//don't include the segment attributes
private static final String NO_SEGMENT_PROP = "BEGIN DBMS_METADATA.SET_TRANSFORM_PARAM(DBMS_METADATA.SESSION_TRANSFORM,'SEGMENT_ATTRIBUTES', false); END;";
//include a sql terminator for each statement
private static final String SQL_TERMINATOR = "BEGIN DBMS_METADATA.SET_TRANSFORM_PARAM(DBMS_METADATA.SESSION_TRANSFORM,'SQLTERMINATOR', true); END;";
private static final String SQL_OJBECTS = "select object_name from user_objects where object_type = 'PACKAGE' and instr(object_name,'TEST')=0 order by 1";
@SuppressWarnings("unchecked")
public static void main( String[] args ) throws IOException
{
long start = System.currentTimeMillis();
EntityManagerFactory emf = Persistence.createEntityManagerFactory(
"DEV");
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
em.createNativeQuery(
NO_SCHEMA).executeUpdate();
em.createNativeQuery(
PRETTY).executeUpdate();
em.createNativeQuery(
NO_PHYSICAL_PROP).executeUpdate();
em.createNativeQuery(
NO_SEGMENT_PROP).executeUpdate();
em.createNativeQuery(
SQL_TERMINATOR).executeUpdate();
List<String> objectNames = (List<String>)em.createNativeQuery(
SQL_OJBECTS).getResultList();
for(String objectName:objectNames){
String ddlSpec = getDDL(em,
"PACKAGE_SPEC",objectName);
write(
"pks."+objectName.toLowerCase()+".sql",ddlSpec);
String ddlBody = getDDL(em,
"PACKAGE_BODY",objectName);
write(
"pkb."+objectName.toLowerCase()+".sql",ddlBody);
}
em.getTransaction().commit();
em.close();
long end = System.currentTimeMillis();
System.
out.printf("Done. Spent %d secs.", (end - start) / 1000);
}
private static String getDDL(EntityManager em,String type,String objectName){
String sql =
"select DBMS_METADATA.GET_DDL('"+"PACKAGE_SPEC"+"','"+objectName+"') from DUAL";
return em.createNativeQuery(sql).getSingleResult().toString();
}
public static void write(String fileStr,String content) throws IOException{
BufferedWriter writer =
new BufferedWriter(new OutputStreamWriter(new FileOutputStream(fileStr)));
writer.append(content);
writer.newLine();
writer.close();
}
}