Programmatically creating a new Entity

User b8496f9459

18-03-2010 16:08:53

Dear Chemaxon folks,


I'm trying to read descriptors from a IJC database, train a classifier on the data, and write the output from the classifier back to the database, into a new Table/Entity.


Reading data and training the classifier works, but I can't figure out how to create a new Entity which IJC will recognize when connecting to the schema. Of course, I can create the table in SQL and promote it using the GUI, but this will become impractical for a large number of Entitys (and it's not very elegant ;) ). I basically need a guided tour through the steps which are necessary to create an Entity. Are there any docs available on that, or can you help me figure out?


Thanks in advance,


Michael

ChemAxon e189db4705

18-03-2010 18:53:07

Michael,


I suppose you already have instance of DFSchema (when you are able to read data using IJC API). So the following code can help you to create standard or jchem entity:


public static DFEntity createJchemEntityForumTopicExample(DFSchema schema) {
        String entityName = "Classifier output data";
        DFEnvironmentRW env = null;
        DFLock lock = null;
        try {
            String operationName = "Creating a new jchem entity";
            // lock DDL (which prevents other threads doing DDL model modifications)
            lock = DIFUtilities.getLockable(schema).obtainLock(operationName);
            // Create a default environment with user interface feedback - this will create a progress bar running in the bottom right corner of IJC window
            env = EnvUtils.createDefaultEnvironmentRW(lock, operationName, false);
            // Prepare newtype - factory object for creating new DIF model artefacts. New Jchem entity in this case.
            DFNewType<DFEntity> nt1 = prepareNewJchemEntityNewType(schema, entityName);
            // Just create the entity. Some new types can create more objects in single create() call, in this case we expect just one entity
            DFEntity e = nt1.create(env).iterator().next();
            return e;
        }
        finally {
            if (env != null) {
                // finish progress bar if it was property started
                env.getFeedback().finish();
            }
            if (lock != null) {
                // unlock DDL so other Threads/actions can modify DDL model
                lock.release();
            }
        }
    }

    private static DFNewType<DFEntity> prepareNewJchemEntityNewType(DFSchema schema, String entityName) {
        // Take all newtypes for creating a new entity. Filter them using DIFUtilities method
        List<DFNewType<DFEntity>> allNTs = DIFUtilities.findAllAppropriateNewTypes(schema.getEntities().getNewTypes(),
                false, // 1. it's for creating of new objects, not promoting existing table
                new Class[] { DBEntityCapability.class, JChemEntityCapability.class }, // We require Jchem+DB type of entity.
                new Class[0]); // If you prefer standard entity, just move JChemEntityCapability.class to this second Class[] array
        assert allNTs.size() == 1; // we expect only one new type. Otherwise criteria for NT search must be changed.
        DFNewType<DFEntity> nt = allNTs.get(0);
        // It's expected that this newtype has options of this "well known" type
        assert nt.getOptions() instanceof DFNewTypeWellKnownOptions.NewJChemBaseEntity;
        // ... so it's possible to cast to it and fill parameters before entity is create...
        DFNewTypeWellKnownOptions.NewJChemBaseEntity nto = (DFNewTypeWellKnownOptions.NewJChemBaseEntity) nt.getOptions();
        // ... only name is important in this case, but you can change other params as well
        nto.setNewDFItemNameSafe(entityName);
        if (!nto.isValid()) {
            // it should not happen, but sometimes filled parametes might be invalid and entity can't be created
            throw new IllegalStateException("error:"+nto.getErrorMessage());
        }
        return nt;
    }





To create fields in this newly created entity use similar approach (DFNEwType). Then you can fill the data using DFEntityDataProvider (I suppose you use it already).


Let me know if you have any other question.


Petr

User b8496f9459

19-03-2010 06:48:46










phamernik wrote:

I suppose you already have instance of DFSchema (when you are able to read data using IJC API).



Hi Petr.


thanks a lot for the code! That will surely help. However, I didn't use DFSchema yet, I was  reading the data using plain SQL. How can I obtain the DFSchema from the database? Looking at the API docs, I found the DFSchemaProvider Interface, but the implementing subclasses have somehow been hiding from my search ;) . Can you point me to a class that implements DFSchemaProvider, and also one that implements DFEntityDataProvider?


Thanks a lot in advance,


Michael

ChemAxon e189db4705

19-03-2010 07:40:11

Hi Michael,


there are two ways, how to obtain the DFSchema instance. The question is whether you already created IJC schema in the database or not? If schema is already created (using Instant JChem application) it means that you have .ijs file in some project and database contains IJC metadata tables (starting with IJC_). Is it this case or you need to create a new IJC schema programatically?


Petr

User b8496f9459

19-03-2010 07:57:53

Hi Petr,


I have created the schema using IJC already, which is convenient for my case. Which class can I use to obtain the DFSchema?


Cheers,


Michael

ChemAxon e189db4705

19-03-2010 08:11:51

Hi Michael,


use this code:


File f = new File(fileName);
DBImplSchemaProvider.PropsProvider propsProvider = DBImplSchemaProvider.createDefaultReadOnlyPropsProvider(f);
DFSchemaProvider schemaProvider = DBImplSchemaProvider.createSchemaProvider(propsProvider);
DFSchema schema = DIFUtilities.connectAutomatically(schemaProvider, someFeedback);

Comments:



Hope this helps.


Petr

User 502b35756d

02-07-2010 09:41:27

Hi,


I tried to use this code, but unfortunately I got the following error. Do you have any idea what I do wrong?


02.07.2010 11:33:21 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
INFO: Loading XML bean definitions from class path resource [META-INF/spring/anonymous-security-template.xml]
Exception in thread "main" java.lang.UnsupportedOperationException: Not supported.
    at com.im.df.impl.db.api.DBImplSchemaProvider$1.rewriteProperties(DBImplSchemaProvider.java:124)
    at com.im.df.impl.db.sprovider.PropsReadState.storeOptions(PropsReadState.java:132)
    at com.im.df.impl.db.sprovider.PropsReadState.proceedToNextState(PropsReadState.java:98)
    at com.im.df.impl.db.sprovider.SchemaProviderImpl.proceedToNextState(SchemaProviderImpl.java:117)
    at com.im.df.api.util.DIFUtilities.connectAutomatically(DIFUtilities.java:1154)
    at addField.main(addField.java:249)


Thanx,


Jan

ChemAxon e189db4705

02-07-2010 10:09:12

Hi,


It looks there must be some other problem before this exception happens. The most likely there were something missing in .ijs file. I guess username and/or password are missing there?


The intention of this code (connect automatically) is to connect to schema without any GUI, which means without any interaction with user. If any important information is missing there (in .ijs file) this process fails.


I think the best way to fix this is try to connect to this schema using Instant JChem and check "remember username/password" checkboxes. Let us know if this helps or not. thank you.


Petr

User 502b35756d

05-07-2010 07:50:10

Thanx a lot, this was the problem.


 


But I got a new one:


05.07.2010 09:45:53 com.im.df.impl.db.sprovider.RegisterCacheState proceedToNextState
INFO: DB schema null: Registering cache for 1 JChemProperties table(s).
Exception in thread "main" java.lang.NoSuchMethodError: chemaxon.jchem.db.StructureCache.removeLogsForExpiredCaches(Lchemaxon/util/ConnectionHandler;Ljava/util/ArrayList;Z)V
    at chemaxon.jchem.db.CacheRegistrationUtil.unRegisterCache(CacheRegistrationUtil.java:130)
    at chemaxon.jchem.db.CacheRegistrationUtil.unRegisterCache(CacheRegistrationUtil.java:103)



I added jchem.jar to the Buildpath and i find there chemaxon.jchem.db.StructureCache, but not the requsted method.

ChemAxon fa971619eb

05-07-2010 13:26:37

I think you are using IJC 5.3.4, but the database has not been upgraded to that version.


You should try connection to the DB with IJC 5.3.4 to update the tables to the correct version. After that you shoudl have more success.


Tim

User 502b35756d

05-07-2010 15:59:06

Yes, I use IJC 5.3.4 But the DB were already updated. Any other suggestion?


Thanx, Jan

ChemAxon fa971619eb

05-07-2010 16:16:40

Looking at that error is seems that the version of jchem being used is not correct. It looks like its an older version of JChem, not the 5.3.4 version that is expected.


Can you double check the version of the JChem libraries that are on the classpath.


You can do this on the commandline by finding the jchem.jar file and executing it like this:


$ java -jar jchem.jar

JChem version: 5.3.4
Table version: 5030300    (for determining if regeneration is necessary)


 


Tim

User 502b35756d

06-07-2010 07:45:18

Yes thanx a lot!


I used Chemaxon/ChemBase/lib/jchem.jar, which is 5.2.5.1 but now I use Chemaxon/InstantJChem/instantjchem/modules/ext which really is 5.3.4


Sorry for all this stupid mistakes and thanx again for your patience.

User 502b35756d

14-07-2010 11:04:07

Hi,


so, as my programm grows, i stil come up with some questions. right now i try to create a view




try {
                 lock = DIFUtilities.getLockable(schema).obtainLock("createView");
                 DFView newView = DIFUtilities.createViewForDataTree(tree, "allodors", false, EnvUtils.createDefaultEnvironmentRW(lock, "ViewCreation", false));

             }

but get the following error:




Exception in thread "main" java.lang.IllegalStateException: Invalid lock: My lock=null. Tested lock=LockSupportImpl [Reason=createView Lockable=LockableSupport[Schema]]
    at com.im.df.impl.db.LockableSupport.checkLock(LockableSupport.java:104)
    at com.im.df.impl.db.DBSchemaUtilities.testUserLockForAddingNew(DBSchemaUtilities.java:116)
    at com.im.df.impl.db.views.NewViewNT.creationParamsTest(NewViewNT.java:92)
    at com.im.df.impl.db.views.NewViewNT.create(NewViewNT.java:96)
    at com.im.df.api.util.DIFUtilities.createViewForDataTree(DIFUtilities.java:394)
    at com.im.df.api.util.DIFUtilities.createViewForDataTree(DIFUtilities.java:383)
    at addField.main(addField.java:132)

Further questions are, how i could delete a view and how i can add a field to a view?


Thanx, Jan

User 502b35756d

14-07-2010 12:50:09

i just figured out, that i of course should have set the createOwnUserLock to true. works fine now.


stil, are there methods to delete a view or to add a field?

ChemAxon e189db4705

14-07-2010 14:49:10

Basic methods for adding or deleting any DFItem (entity, datatree, field, view, etc.) are in DFContainer interface.


The hierarchy of DFItems is briefly this: The root object is DFSchema, which contains zero or more DFEntity, DFDataTree, DFRelationship. Each DFEntity have some DFField and each DFDatatree contains zero or more DFView (gridview or form). There are also others DFItem types.


If you have  an DFEntity instance and want to create a new field you must take DFContainer first:


DFContainer<DFField> containerOfFields = myEntity.getFields();

For creating new fields there are so called DFNewTypes. For example there is a new type for creating new integer field (plus a new DB column), a new type for for text field, etc.  You will need to find appropriate new type, then fill options (like name of this new field) and then call create() mehtod on this newtype instance. This is partly described in this API example.


For creating a new views (I mean gridview or form) it's similar, but you must take DFContainer<DFView> from appropriate DFDataTree instance first. The method in DIFUtilities is just simplification for creating a new view, but it delegates to these new types.


To delete any object there is also method in DFContainer: remove(..). It might be also useful to ask isDeteleAllowed() method first.