Skip to content
accelerando

Tag Archives: Java

JDBC: Get autogenerated keys on a Oracle DB

09-Oct-07

With the current and latest Oracle JDBC Drivers it’s possible to retrieve one automatically generated key based on a sequence or any other arbitrary value (autogenerated-keys or identity columns in other databases).

Certainly it isn’t as simple as just use using Statement.html#getGeneratedKeys() as it simply returns an emtpy resultset.

After browsing around, i saw that java.sql.Connection can prepare a statement with a flag to return generated keys like so:

connection.prepareStatement("INSERT INTO FOOBAR VALUES(id.nextval, 1), Statement.RETURN_GENERATED_KEYS);

(By the way, it’s always a good idea to use prepared statements from a performance point of view as they can be reused)

Anyway, it wouldn’t be an Oracle product if something is different like any other products and i still was left alone in the dark with an empty result set.

Follow the path to enlightment:

final String sql = "INSERT INTO foobar(id, b) VALUES (id.nextval, ?)";
stmt = connection.prepareStatement(sql,new String[]{"ID"});			
stmt.setString(1, "bar");
stmt.execute();		
rs = stmt.getGeneratedKeys();
rs.next();
rv = rs.getInt(1);

Telling oracle which column contains the generated value does the trick. It’s really well hidden on their website. Be aware, you cannot refer to the returned keys by name, you need to address them 1 based.

Be aware that this doesn’t work inside a 9.2.x.x or 10.2.x.x Oracle Database as a Java Stored Procedure. Either the driver isn’t JDBC 3 (9.2) or the methods are not supported (10.2). You can work around this problem with 2 statements, first select id.nextval from somewhere, then execute your insert. Lame, but i didn’t find any other solution.

Ran on the client side with the latest JDBC from Oracle on the other hand works just fine.

The Pan-Computer-Programming-Language Conference

05-Oct-07

Ruby (grabbing the microphone): Um so yeah I’d just like to kick this bad boy off by saying that THE REST OF YOU SUCK A**!!! Yeah, I said it! The A-word! A**! Oh yeah! Boom, baby! Woo! Ruby FTW!

Read the whole conference here, found at the gay bar.

On Java Threads: A fairytale of a tutorial

12-Jul-07

I always thought that the Java Thread API is something… strange. If you work in a frontend application, things like running long-running tasks in the back without having the GUI ugly frozen and not responding should be somewhat simpler.

SwingWorker has been around for quite a time but made it just recently into the core API (Java6). Furthermore i don’t think that it’s the right thing for performing enduring tasks like checking for mail and pushing a result with a second thread into a database, for example.

Don’t get me wrong, i use SwingWorker quite often, but it didn’t fit my needs and furthermore, i wanted to learn more about Java Threads.

My goal / task was a little daemon that regularly checks an email account and a samba share for some files, load them into an Oracle Database and executes a longer running db procedure. The checking should be suspendable and stoppable independently, the configuration should be reloadable.

I throw some interfaces and abstract classes at the vm and boom, it was that simple ;)

Things i’ve learned:

  • Always start the GUI in it’s own thread, never use the main thread. Sure, most programs will work fine, but it can get confusing. Use SwingUtilities to do so.
  • A thread once terminated is not reusable. Never ever. So don’t interrupt them if you plan on resume them later.
  • Know the primitives, i.e. build in locks (synchronized and wait())
  • Know the task scheduling frameworks (Executors and ExecutorServices)
  • Read the tutorials here, here and maybe here

The following demo can start 7 producers and one consumer, both are synchronized via a BlockingQueue (i actually used a SynchronousQueue at work, as the files must only be removed if they were taken by the db). Both the producers and consumers can be suspended, resumed and stopped. I never ever will start a thread by hand again if not necessary. The threads are managed by an ExecutorService.

For the tasked mentioned above this thing works fine. If anyone comes up with a better idea, let me know.

I had fun to write it, maybe you have fun to read. Be aware, the program is not a good example of organizing classes, i put everything in one file just for the sake of being a demo.

But apart from that, the demo could serve as an example of what came to Java with Java 5 and 6 as i use a lot of generics, enums and enhanced for loops, in case you haven’t seen this.

To compile and run the stuff you need at least a Java5 JDK (get it here, download this file JThreadDemo.zip, unzip it and type

javac snow/white/JThreadDemo.java
java snow.white.JThreadDemo

If you read this, i’ll guess you’re familiar with the JDK, java packages and the whole crap.

Get the whole fun after the click:

More…

Rails and Grails revisited

25-Jun-07

I’ve never thought that my little little post would made such an impact.

While writing that post i was frustrated explaining the Spring configuration to my colleaques again, i was frustrated over the url mappings and so the post was a little harsh.

I don’t think that Hibernate is inferior to Active Record, regarding Spring and ActionController, i cannot tell, i like ActionController just better.

Anyhow, bring all three parts, model, view and controller, together… And see where Rails shines: In ease of use and working right out of the box. No wonder they came up with this whole screencasting things (at least, i never saw this before), it’s just impressing.

Instead of pushing out framework after framework, view technology after view technology (Faces, ADF, etc.), they bundled working things together and i think that’s what people like about RoR.

And i guess there’s a need for such think on the Java side of life as well… If not, why is the Grailsteam working on Grails? To paraphrase my last post positive: They bring good things in a nice package together.

For getting me into groovy i must thank the people behind Grails, this stuff is really cool.

For further reading i recommend the following posts:

Apart from this, can please anyone assure me, that some of the questions on the SCJP exam are a little weird and not really from this world? ;)

Using Hibernate with Oracle Spatial

05-Feb-07

Oracle Spatial Datatype JGeometry from the spatial api (which can be found here) can easily be used with hibernate through a custom dialect and a custom type that delegates to an instance from oracle sdo api. Everything that is needed is here:

Mapping Spatial Oracle type SDO_GEOMETRY to JGeometry

The only quirk with this solution as of February 2007 is the fact, it won’t work with null columns. The fault lies in nullSafeSet. Either can the JGeometry delegate be null or, what is worse, preparedStatement.setNull( i, Types.OTHER); will fail with an invalid column type. The correct version of this method is as follows:

public void nullSafeSet( PreparedStatement preparedStatement, Object o, int i) throws HibernateException, SQLException {
  if( o == null) {
    preparedStatement.setNull(i, Types.STRUCT, "MDSYS.SDO_GEOMETRY");
  } else {
    if( o instanceof JGeometryType) {
      JGeometryType gt = (JGeometryType) o;
      OracleConnection oc = (OracleConnection) preparedStatement.getConnection().getMetaData().getConnection();
      if(gt.getJGeometry() == null)
        preparedStatement.setNull(i, Types.STRUCT, "MDSYS.SDO_GEOMETRY");
      else
        preparedStatement.setObject( i, JGeometry.store( (JGeometry) (gt).getJGeometry(), oc));   
    }
  }
}

Furthermore, i think the spatial dialect should be registered with the following class:

public class OracleSpatialDialect extends Oracle9Dialect {
	public OracleSpatialDialect() {
    super();
      registerColumnType( Types.OTHER, "MDSYS.SDO_GEOMETRY");
  }
}

Kudos to Joel Schuster from Navisys for the adapter class!

On writing binary data from within Oracle Forms 6i

29-Jan-07

There is this nice project of ours from 2002…. developed with Oracle Forms 6i and database PL/SQL Procedures. This project runs fine with an estimated 6gig database. Plain old client server model.

We have some XML / XSLT based HTML reports that are processed – thanks to Oracle 9i – directly in the database with packages dbms_xmlgen and xmlparser. Data is collected in a mere handful of so called “object views”, that are denormalized, hierarchical views on data.

After receiving the assignment to generate pdf it was no big problem at all to write some java classes around iText and dom4j to generate new reports.
I decided agains xsl-fo as i found no inexpensive tools for easily designing adequate stylesheets. For the worse, xsl-fo lacks several important features, i.e. collapsing borders. My customers would have laughed at best if i had presented the prototype…

So i have this java classes – all in the database for sure, no need for java on the client side -, i have added code to my package and i thought it would be easy to write the resulting blob with Forms 6i to the client…

Bah! There is no such easy thing in Forms. I remembered havin’ problems reading a clob, as the whole bunch of dbms_lob functionality doesn’t work in forms… So my workaround for creating text files from clobs was on the database side:

PROCEDURE  read_export(
  p_export_id  IN     NUMBER,
  p_menge      IN OUT BINARY_INTEGER,
  p_offset     IN     BINARY_INTEGER,
  p_buffer     IN OUT VARCHAR2
) IS
 clInhalt  CLOB;
 BEGIN
  BEGIN
    SELECT processed_export
      INTO clInhalt
      FROM xmlt_exporte
     WHERE export_id = p_export_id;
    DBMS_LOB.READ(clInhalt, p_menge, p_offset, p_buffer);
  EXCEPTION
    WHEN NO_DATA_FOUND THEN
      p_menge:= 0;
  END;
EXCEPTION
  WHEN OTHERS THEN
    p_menge := 0;
END;

and in a forms on client side:

fhDateiOut := text_io.fopen(vcPath || vcFile, 'W');   	  	   	
LOOP			
  pck_xml.read_export(p_export_id, i, offset, vcBuffer);
  EXIT WHEN i = 0;
  offset := offset + i;
  text_io.put(fhDateiOut, vcBuffer);
END LOOP;					   
text_io.fclose(fhDateiOut);

(text_io is a forms standard package).

This works quite well.. So i thought, well, d2kwutil has some functions to write binary files, so i copy the database procedure, use dbms_lob.read with blob and raw and i’m done…
Yeah, i was done. Well fucked off.

I have no idea in which way dbms_lob.read converts blob data to raw, but it’s everything but the original. So after banging my head against the wall, finding things like “use software developed in this century” in forums, i wrote the following java code:

final BASE64Encoder enc = new BASE64Encoder();
 
final CLOB rv = CLOB.createTemporary(tmp.getJavaSqlConnection(), true, CLOB.DURATION_SESSION);
 
int bufSize = 1024*1024*1;
 
final BufferedInputStream in = new BufferedInputStream(tmp.getBinaryStream(), bufSize * 2);        
final BufferedOutputStream out = new BufferedOutputStream(rv.setAsciiStream(0L), bufSize);
 
enc.encode(in, out);
out.flush();
out.close();

which runs in the database, takes a blob as parameter and base64 encodes it to a clob. This clob is written to my export table and read by forms in the above way. Then i have a little base64.exe along with my forms that is called from within forms that decodes the file….

So much trouble just for writing binary data from server to client… it’s a twoliner with c or java.

JComboBoxes auf maximale Größe bringen

09-Nov-06

Manchmal ist es praktisch, wenn eine JComboBox keinen Scrollbalken mehr hat. Ist bei extrem vielen Einträgen natürlich nicht sinnvoll, aber bei einer überschaubar großen Zahl schon:

iimport javax.swing.JComboBox;
 
public class Blah {
	public void blub() {
		final JComboBox combo = new JComboBox();
		combo.setMaximumRowCount(combo.getModel().getSize());
	}
}

Zack! und schon ist der Scrollbalken weg.

Kaputte UTF-8 Daten im Servlet

05-Oct-06

Beruflich habe ich gerade mit einer Webanwendung zu tun, die mit Spring realisiert ist. Spring macht ähnlich viel Spaß wie Ruby und ist bis jetzt das erste J2EE Framework, dass mir von Anfang zusagte und es auch schaffte, mich zu begeistern.

Die Webanwendung ist komplett UTF-8 basiert. Soweit so gut. Leider mußte ich feststellen, dass Eingaben per form nicht so ankamen, wie ich mir das vorgestellt hatte, irgendwo ging das Characterset verloren.

Ich nutze zur Zeit Java 1.5.0.8, Apache Tomcat 5.5.17, Spring 1.2.8 sowie Hibernate 3.1.x. Irgendwo im Zusammenspiel der ersten drei Komponenten trat der Fehler auf, obwohl ich in allen beteiligten JSP Dateien den Content Type angegeben habe. Ich habe mir jetzt mit folgenden Filter beholfen, der dafür sorgt, dass UTF-8 auch als solches ankommt:

package filter;
 
import java.io.IOException;
 
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
 
public class CharsetFilter implements Filter {
	FilterConfig config;
	String encoding = "UTF-8";
 
	/**
	 * @see javax.servlet.Filter#destroy()
	 */
	public void destroy() {
	}
 
	/**
	 * Sets the character encoding on the request
	 * @see javax.servlet.Filter#doFilter(javax.servlet.Servle tRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain)
	 */
	public void doFilter(ServletRequest request, ServletResponse response,
			FilterChain chain) throws IOException, ServletException {
		request.setCharacterEncoding(encoding);
		chain.doFilter(request, response);
	}
 
	/**
	 * @see javax.servlet.Filter#init(javax.servlet.FilterConf ig)
	 */
	public void init(FilterConfig config) throws ServletException {
		this.config = config;
		this.encoding = config.getInitParameter("requestEncoding");
	}
}

Der Filter kann im web.xml einfach konfiguriert werden:

<filter>
	<filter-name>
		charsetFilter
	</filter-name>
	<filter-class>
		filter.CharsetFilter
	</filter-class>
	<init-param>
		<param-name>requestEncoding</param-name>
		<param-value>UTF-8</param-value>
	</init-param>
</filter>
 
<filter-mapping>
	<filter-name>charsetFilter</filter-name>
	<url-pattern>/app/html/*</url-pattern>
</filter-mapping>

Spring und JNDI Datasources

21-Sep-06

Ich nutze gerade das J2EE Framework Spring zusammen mit Hibernate und Oracle für eine Webanwendung.

Die Hibernate DataSource kann entweder über eine DriverManagerDataSource und Angabe der Verbindungsparameter innerhalb der Webanwendung gesteuert werden, oder es kann eine JNDI Datasource des Application Containers (in dem Fall Tomcat) genutzt werden:

<bean id="serverDataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
	<property name="jndiName"  value="java:comp/env/jdbc/blah"/>
</bean>

Der Trick dabei ist, den vollständigen Namen der DataSource anzugeben, also “java:comp/env/jdbc/blah” statt “jdbc/blah”, ansonsten bekommt nur “javax.naming.NameNotFoundException: Name jdbc is not bound in this Context” um die Ohren geschlagen, auch wenn man die DataSource im Tomcat konfiguriert hat.

Bah, das sowas immer soviel Zeit kosten muss….

Oracle JDBC Driver und AspectJ

26-Jul-06

Edit for non-german speakers:
This is a solution for “java.lang.ClassNotFoundException: oracle.security.pki.OracleWallet” or “java.lang.ClassNotFoundException: oracle.security.pki.OracleSecretStore”

The Oracle OJDBC driver is missing the two classes oracle.security.pki.OracleWallet and oracle.security.pki.OracleSecretStore. Normally not a problem but with a class loader that preloades all referenced classes, runtime will certainly fail. A work around is to create these to classes as stubs with the exact package name. That will do the trick.

Edit: As an alternative, you can add ${ORACLE_HOME}/jlib/oraclepki.jar to your classpath if you did a full install of a recent oracle client.

Der Oracle OJDBC Treiber hat mir mittlerweile schon mehr als einmal Ärger bereitet.

Der vorläufge Höhepunkt ist sein Nichtfunktionieren im Zusammenhang mit dem Load Time Weaving Class Loader aus dem AspectJ Projekt.

Dem normalen Java Classloader fällt es nicht auf, wenn ich per Class.forName “oracle.jdbc.driver.OracleDriver”, dass zwei Klassen fehlen: oracle.security.pki.OracleWallet und oracle.security.pki.OracleSecretStore. Dem Weaving Classloader hingegen schon.

Ich weiß nicht, was diese beiden Klassen machen, ich sehe nur, dass die entsprechende private Methode in OracleDriver unweigerlich auf einen Fehler laufen muss, so sie denn benutzt wird.

Jedenfalls, das Weaving schlägt fehl, bums, aus die Maus mit LTW Aspekten.

Auf dem Klo hatte ich die simple Idee, einfach in meinem Projekt obige Klassen leer anzulegen. Und siehe da: Wenn sie im Klassenpfad sind, kann ich OracleDriver instanzieren und alle sind glücklich.

Edit: Als Alternative kann man auch ${ORACLE_HOME}/jlib/oraclepki.jar zum Klassenpfad hinzufügen, falls man eine vollständige Installation eines halbwegs aktuellen Oracle Clients hat.

Close
E-mail It