Plugin creating new list

User faea122c03

13-01-2008 18:54:01

Hi, everyone!





I'm writing the a IJC plugin that should create a new list during its work. I began from AddField tutorial. I tried creating a new list by the following code:





List<DFNewType<DFList>> allNewTypes = entity.getLists().getNewTypes();





if (allNewTypes.isEmpty()) {


return;


}





final DFNewType<DFList> nt = allNewTypes.get(0);








UIBackgroundRunnerRW runner = new UIBackgroundRunnerRW(DIFUtilities.getLockable(entity, true), "Selecting List", false) {





public void phase1InRequestProcessor() {





Collection<DFList> newLists = nt.create(getEnvironment());


}


@Override


public void phase2InAWT() {


selectRecords(entity);


}


};





When I run this plugin I receive the null pointer exception in the create method. Earlier (in previous versions) this method failed with invalid lock exception. How can I overcome these troubles

ChemAxon fa971619eb

14-01-2008 08:06:09

Please could you provide the stack trace of the NPE?





Thanks


Tim

ChemAxon e189db4705

14-01-2008 08:53:29

I tried to create a new list the same way as you are doing it and found that there is really a NullPointerException. Unfortunately we haven't seen it before as we always create list with some initial values (so this bug can't be reproduced in Instant JChem, only if you use DIF APIs). If you don't specify any values, then initial list is null and it causes this NPE in our code.


I already fixed the problem and the problem will be resolved in 2.2.1 very soon, but in the meantime, there is a trivial workaround you can use to prevent the NPE in your code. Try to set initial values of the list to "new ArrayList()".





Code:
        List<DFNewType<DFList>> allNewTypes = entity.getLists().getNewTypes();


        if (allNewTypes.isEmpty()) {


            return;


        }


        final DFNewType<DFList> nt = allNewTypes.get(0);


        Object options = nt.getOptions();


        if (options instanceof DFNewTypeWellKnownOptions.NewList) {


            DFNewTypeWellKnownOptions.NewList opt = (DFNewTypeWellKnownOptions.NewList) options;


            opt.setNewDFItemNameSafe("my new list");





            // workaround - the NullPointerException will be fixed if you specify any non-null list


            opt.setValues(new ArrayList());





            /*


            // or optionally fill your list values here before list is created:


            List ids = new ArrayList();


            for (int i = 1; i <= 10; i++) {


                ids.add(i);


            }


            opt.setValues(ids);


            */


        }





        UIBackgroundRunnerRW runner = new UIBackgroundRunnerRW(DIFUtilities.getLockable(entity, true), "Selecting List", false) {


            public void phase1InRequestProcessor() {


                Collection<DFList> newLists = nt.create(getEnvironment());


            }





            @Override


            public void phase2InAWT() {


                //selectRecords(entity);


            }


        };


        runner.start();


User faea122c03

21-01-2008 12:21:07

phamernik wrote:
I tried to create a new list the same way as you are doing it and found that there is really a NullPointerException. Unfortunately we haven't seen it before as we always create list with some initial values (so this bug can't be reproduced in Instant JChem, only if you use DIF APIs). If you don't specify any values, then initial list is null and it causes this NPE in our code.


I already fixed the problem and the problem will be resolved in 2.2.1 very soon, but in the meantime, there is a trivial workaround you can use to prevent the NPE in your code. Try to set initial values of the list to "new ArrayList()".





Code:
        List<DFNewType<DFList>> allNewTypes = entity.getLists().getNewTypes();


        if (allNewTypes.isEmpty()) {


            return;


        }


        final DFNewType<DFList> nt = allNewTypes.get(0);


        Object options = nt.getOptions();


        if (options instanceof DFNewTypeWellKnownOptions.NewList) {


            DFNewTypeWellKnownOptions.NewList opt = (DFNewTypeWellKnownOptions.NewList) options;


            opt.setNewDFItemNameSafe("my new list");





            // workaround - the NullPointerException will be fixed if you specify any non-null list


            opt.setValues(new ArrayList());





            /*


            // or optionally fill your list values here before list is created:


            List ids = new ArrayList();


            for (int i = 1; i <= 10; i++) {


                ids.add(i);


            }


            opt.setValues(ids);


            */


        }





        UIBackgroundRunnerRW runner = new UIBackgroundRunnerRW(DIFUtilities.getLockable(entity, true), "Selecting List", false) {


            public void phase1InRequestProcessor() {


                Collection<DFList> newLists = nt.create(getEnvironment());


            }





            @Override


            public void phase2InAWT() {


                //selectRecords(entity);


            }


        };


        runner.start();


Thank you! This really works! Here's another question. I set the list values using setValues(List, DFEnvironment) method from DFList class. However, I want my plugin not only to create a new list but also to execute this list. Which code should I use in order to execute the list by plugin?

ChemAxon e189db4705

22-01-2008 11:13:19

The list can be applied using DFResultSet.applyList() method. You need to lock this instance of DFResultSet before this method is called - or use UIBackgroundRunner for example.





The question is how to obtain the result set instance and how to get the list which you want to apply. Each DFList belongs to some DFEntity. Each DFEntity can be used as root in more DFDataTrees. Currently each DFDataTree has only one DFResultSet - so this result set is shared among all DFViews of this DFDataTree. You can obtain it using getDefaultResultSet method.





That's from DIF point of view (non visual). In Instant JChem most of the actions are context sensitive. So each action can ask what the current context (selection) represents and enable or disable itself according to this context. You want to apply some DFList to some DFResultSet.





When you click to Lists&Queries component and select some list then current context represents DFList (using GenericListCookie interface). On the other hand if you open Form or Grid view, appropriate DFDatatree and it's DFResultSet are in current context.





I created an example action which depends on DFResultSet in current selection (actually DFResultSet.VertexState, but it's similar). The action takes the current result set, find its root DFEntity, create a sample list and then applies it to the result set. Hope this helps.

User faea122c03

27-03-2008 11:23:07

Thanks!!!


This really works.


Now Ihave another question. I'm writing a plugin creating a query and applying this query to a database. For this purpose I wrote following code:





private void createNewList(DFEntity entity, String filename) {


final DFTermExpression expr = DFTermsFactory.createFieldOperatorValueExpr(Operators.IN_LIST, sField, null, idlist);


final DFResultSet rs = vs.getResultSet();


final DFLock rsLock = rs.getLockable().obtainLock("Apply list");


UIBackgroundRunnerRW runner = new UIBackgroundRunnerRW(DIFUtilities.getLockable(entity, true), "Selecting List", false) {


public void phase1InRequestProcessor() {


DFEnvironmentRW envForApplyList = EnvUtils.createRWFromRO(getEnvironment(), rsLock);


rs.applyQuery(expr, envForApplyList);


//rs.applyWorkingQuery(envForApplyList);


}





@Override


public void phase1Finally() {


if (rsLock != null) {


rsLock.release();


}


}





@Override


public void phase2InAWT() {


//selectRecords(entity);


}


};


runner.start();


}





However I can not compile this code. I get the error message:





Compiling 1 source file to E:\Work\src\SelectList2\build\classes


E:\Work\src\SelectList2\src\com\im\ijc\selectlist2\SelectListAction.java:119: applyQuery(com.im.df.api.dml.DFTermHandle,com.im.df.api.support.DFEnvironmentRW) in com.im.df.api.dml.DFResultSet cannot be applied to (com.im.df.api.dml.DFTermExpression,com.im.df.api.support.DFEnvironmentRW)


rs.applyQuery(expr, envForApplyList);


1 error


C:\Program Files\NetBeans 6.0\harness\common.xml:116: Compile failed; see the compiler error output for details.





What is wrong in my code? How Can I fix it?





Also another question. I have an array of a few hundreds (or thousands) string values and I want to create DFTermExpression with IN_LIST operator and all these values as operands. How can I pass them to DFTermsFactory.createFieldOperatorValueExpr method, as a string array, as java list or as DFList?

ChemAxon e189db4705

31-03-2008 02:32:00

vdub wrote:



Compiling 1 source file to E:\Work\src\SelectList2\build\classes


E:\Work\src\SelectList2\src\com\im\ijc\selectlist2\SelectListAction.java:119: applyQuery(com.im.df.api.dml.DFTermHandle,com.im.df.api.support.DFEnvironmentRW) in com.im.df.api.dml.DFResultSet cannot be applied to (com.im.df.api.dml.DFTermExpression,com.im.df.api.support.DFEnvironmentRW)


rs.applyQuery(expr, envForApplyList);


1 error


I guess you have old version of IJC, because DFTermHandle class was removed almost half year ago. Could you check you work with IJC 2.2.x only? In the current version of IJC applyQuery method takes DFTermExpression as the first parameter.
vdub wrote:



Also another question. I have an array of a few hundreds (or thousands) string values and I want to create DFTermExpression with IN_LIST operator and all these values as operands. How can I pass them to DFTermsFactory.createFieldOperatorValueExpr method, as a string array, as java list or as DFList?
The method declaration is:





Code:
public static DFTermExpression createFieldOperatorValueExpr(DFOperator operator, DFField field, Map<String, Object> options, Object ... values)



It means that as values you can pass there any number of parameters or standard array of Objects. All these calls should work:


Code:



term = createFieldOperatorValueExpr(op, field, options);


term = createFieldOperatorValueExpr(op, field, options, "abc");


term = createFieldOperatorValueExpr(op, field, options, "abc", "def");


term = createFieldOperatorValueExpr(op, field, options, new Object[] { "abc", "def" });








In your case, convert it to array and pass as single parameter.





Let me know, please, if this helps.


Petr

User faea122c03

28-05-2008 08:15:43

phamernik wrote:
vdub wrote:



Compiling 1 source file to E:\Work\src\SelectList2\build\classes


E:\Work\src\SelectList2\src\com\im\ijc\selectlist2\SelectListAction.java:119: applyQuery(com.im.df.api.dml.DFTermHandle,com.im.df.api.support.DFEnvironmentRW) in com.im.df.api.dml.DFResultSet cannot be applied to (com.im.df.api.dml.DFTermExpression,com.im.df.api.support.DFEnvironmentRW)


rs.applyQuery(expr, envForApplyList);


1 error


I guess you have old version of IJC, because DFTermHandle class was removed almost half year ago. Could you check you work with IJC 2.2.x only? In the current version of IJC applyQuery method takes DFTermExpression as the first parameter.
vdub wrote:



Also another question. I have an array of a few hundreds (or thousands) string values and I want to create DFTermExpression with IN_LIST operator and all these values as operands. How can I pass them to DFTermsFactory.createFieldOperatorValueExpr method, as a string array, as java list or as DFList?
The method declaration is:





Code:
public static DFTermExpression createFieldOperatorValueExpr(DFOperator operator, DFField field, Map<String, Object> options, Object ... values)



It means that as values you can pass there any number of parameters or standard array of Objects. All these calls should work:


Code:



term = createFieldOperatorValueExpr(op, field, options);


term = createFieldOperatorValueExpr(op, field, options, "abc");


term = createFieldOperatorValueExpr(op, field, options, "abc", "def");


term = createFieldOperatorValueExpr(op, field, options, new Object[] { "abc", "def" });








In your case, convert it to array and pass as single parameter.





Let me know, please, if this helps.


Petr
Thanks! This really works.