2

This is a continuation of the issue described in Using eclipselink in Java code run from MATLAB and is similar to the issue described in Java JPA Class for MATLAB, but the accepted solutions described there have not completely solved the issue.

I am trying to use eclipselink to connect to an oracle database in matlab. From the answers in the previous posts, I put the code on the static classpath (in the classpath.txt). When I do this I am able to use it, but only if I create the EntityManager (via a call to Persistence.createEntityManager(...)) within the first few seconds after matlab loads. If I wait more than 5 second after starting up Matlab, the exact same code gives the "No Persistence provided" exception. I have confirmed that the times that it does work, it is actually using a different class loader than the times that it does not. The only thing that I can think of is that the classpath is initializing on a separate thread than the Matlab console and that if I run it quickly, then Matlab's OSGI classloader is not initialized yet so it uses the default java class loader.

This is obviously not an acceptable solution and doesn't seem to have really solved the reason of why Matlab classloader can not find the persistence.xml. Does anyone have any further ideas? Could it possibly be in how I am initializing eclipselink? Neither the guy that worked on this code before me nor I have been able to figure out a way to get it to recognize the persistence.xml in any way other than putting it in the META-INF folder on the classpath.

Community
  • 1
  • 1
Sam
  • 322
  • 2
  • 11

2 Answers2

2

eclipselink is available in two flavors:

  1. "Intended for use in Java EE and SE environments." and
  2. "OSGI Bundle Zip to use EclipseLink 2.1.2 runtime in an OSGi container."

The "OSGI Bundle" will not run on the MATLAB JVM due to the missing OSGI container. Therefore the single jar for Java EE and SE environments will be the right choice.

According to Deploying EclipseLink putting persistence.xml in the META-INF folder on the classpath, seems to be correct.

EDIT:

The following lines are added to startup.m whereas ClassPathHacker.class must reside in /MATLAB/java/. All three required libraries derby.jar, eclipselink.jar, javax.persistence_2.0.1.v201006031150.jar may be download from the locations given in JPA 2.0 with EclipseLink Tutorial.

javaaddpath('/MATLAB/java/');
ClassPathHacker.addFile(java.lang.String('/NetBeansProjects/JpaForMatlab/dist/JpaForMatlab.jar'))
ClassPathHacker.addFile(java.lang.String('/NetBeansProjects/JpaForMatlab/lib/derby.jar'))
ClassPathHacker.addFile(java.lang.String('/NetBeansProjects/JpaForMatlab/lib/eclipselink.jar'))
ClassPathHacker.addFile(java.lang.String('/NetBeansProjects/JpaForMatlab/lib/javax.persistence_2.0.1.v201006031150.jar'))

JpaForMatlab.jar has the following layout:

|- META-INF
   |- persistence.xml
|- jpaformatlab
   |- Main.class
   |- Todo.class

persistence.xml

<?xml version="1.0" encoding="UTF-8" ?>
<persistence xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
    version="2.0" xmlns="http://java.sun.com/xml/ns/persistence">
    <persistence-unit name="todos" transaction-type="RESOURCE_LOCAL">
        <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
        <class>jpaformatlab.Todo</class>
        <properties>
            <property name="javax.persistence.jdbc.driver" value="org.apache.derby.jdbc.EmbeddedDriver" />
            <property name="javax.persistence.jdbc.url"
                value="jdbc:derby:/NetBeansProjects/derby-db/simpleDb;create=true" />
            <property name="javax.persistence.jdbc.user" value="test" />
            <property name="javax.persistence.jdbc.password" value="test" />
            <property name="eclipselink.ddl-generation" value="create-tables" />
            <property name="eclipselink.ddl-generation.output-mode" value="both" />
        </properties>
    </persistence-unit>
</persistence>

Main.java

package jpaformatlab;

import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.persistence.Query;

public class Main {

    private static final String PERSISTENCE_UNIT_NAME = "todos";
    private static EntityManagerFactory factory;

    public static void main(String[] args) {
        factory = Persistence.createEntityManagerFactory(PERSISTENCE_UNIT_NAME);
        EntityManager em = factory.createEntityManager();
        // Read the existing entries and write to console
        Query q = em.createQuery("select t from Todo t");
        List<Todo> todoList = q.getResultList();
        for (Todo todo : todoList) {
            System.out.println(todo);
        }
        System.out.println("Size: " + todoList.size());

        // Create new todo
        em.getTransaction().begin();
        Todo todo = new Todo();
        todo.setSummary("This is a test");
        todo.setDescription("This is a test");
        em.persist(todo);
        em.getTransaction().commit();

        em.close();
    }
}

Todo.java

package jpaformatlab;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

@Entity
public class Todo {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String summary;
    private String description;

    public String getSummary() {
        return summary;
    }

    public void setSummary(String summary) {
        this.summary = summary;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    @Override
    public String toString() {
        return "Todo [summary=" + summary + ", description=" + description
                + "]";
    }

}

Finally we call the main method in order to run this simple example from the MATLAB prompt.

>> jpaformatlab.Main.main(javaArray('java.lang.String',1))
>> Todo [summary=This is a test, description=This is a test]
Community
  • 1
  • 1
zellus
  • 9,617
  • 5
  • 39
  • 56
  • I tried using the OSGI bundles, but got a number exceptions on IPL along the lines of "Unresolved constraint in bundle 15: package; (package=org.xml.sax.ext)". I tracked down where these packages are supposed to be provided from and they seem to be basic java. They are on the classpath, but don't seem to be being exported by Matlab. Any ideas how to get these dependancies happy? – Sam Dec 14 '10 at 20:52
  • 1
    @Sam: MATLAB does NOT run with the "OSGI Bundle". You should use the single jar for "Java EE and SE environments". – zellus Dec 14 '10 at 21:37
  • @zellus: Thank you, that saves me a bunch of hassle trying to get that working. Unfortunately it leaves me in the same situation where I can't get the classloader to recognize the persistence.xml unless I do it immediately on Matlab startup. – Sam Dec 15 '10 at 15:35
  • @Sam: Could you please put the *persistence.xml* file in the META-INF directory of your eclipselink package, and add the package as first entry to MATLAB's *classpath.txt* file. – zellus Dec 15 '10 at 19:44
  • @zellus: Do you mean the eclipselink package as in repacking the eclipselink.jar with it or do you mean putting it in the META-INF directory of the package that uses eclipselink? I have tried many variations of putting it in the META-INF folder of my own package and putting that and the eclipselink.jar at the top of classpath.txt, but I have not yet tried actually changing the library jar files. I will try that and see what happens. – Sam Dec 16 '10 at 16:44
  • I tried adding to the eclipselink.jar and that wouldn't even get as far as the persistence exception. – Sam Dec 16 '10 at 17:50
2

I found a solution that works though I am not terribly happy with it. When the PersistenceProviderResolverHolder is first initialized it constructs a private inner class called DefaultPersistenceProviderResolver that when asked will find the persistence.xml in your META-INF directory. Later, when you call Persistence.createEntityManagerFactory() it will ask the PersistenceProviderResolverHolder for the resolver and then ask the resolver to find the persistence.xml.

The issue when you run this in Matlab is that at some time during initialization the PersistenceProviderResolverHolder is given an Activator class that replaces the default resolver. As far as I can tell, this Activator class tries to use OSGI to find any persistance configurations. Optimally I should be able to configure things such that it would also find the persistence.xml, but so far I have been unsuccessful at this.

The solution that I came up with is to make my own copy of the DefaultPersistenceProviderResolver class and set an instance of that as the resolver in the PersistenceProviderResolverHolder. This will replace the Activator class that had been put into it and return it to looking for the persistence.xml in the META-INF folder. I really don't like doing this, but it is the only solution that I have been able to get to work in a week of working on this.

Sam
  • 322
  • 2
  • 11